Updating constraints in swift 5 - swift

I have tried deactivating and reactivating... However I cannot seem to find out how to do it... I have code to use as an example but it keeps failing me, if anyone knows how to update a constraint in swift 5 please let me know... I know that the updateConstraint() exists just not sure how to use it.
let constraint1: NSLayoutConstraint? = text.bottomAnchor.constraint(equalTo: view.bottomAnchor)
let constraint2: NSLayoutConstraint? = text.bottomAnchor.constraint (equalTo: view.bottomAnchor, constant: 5)
if acondition {
constraint1?.isActive = false
constraint2.isActive = true
} else {
constraint2.isActive = false
constraint1.isActive = true
}

first declare the variable, after set start constraints variable to true and after call a function that active and dis active constraints, try with my example:
under controller class declare a button and a view do you want to move:
let dummyView = UIView()
let button = UIButton(type: .system)
after declare variable to move your view with constraint:
var up: NSLayoutConstraint?
var down: NSLayoutConstraint?
in ViewDiLoad set the view, the button and the constraints like this:
dummyView.backgroundColor = .yellow
dummyView.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("viewDiwn", for: .normal)
button.backgroundColor = .red
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 16)
button.addTarget(self, action: #selector(handletapButton), for: .touchUpInside)// button action that call handletapButton func
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(dummyView)
up = dummyView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
up?.isActive = true // start constraint active
down = dummyView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100) // constraint to activate for move the view
dummyView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
dummyView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
dummyView.heightAnchor.constraint(equalToConstant: 50).isActive = true
view.addSubview(button)
button.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
button.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
now write the function to move the view by constraint animation:
#objc func handletapButton() {
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
self.up?.isActive = false
self.down?.isActive = true
self.view.layoutIfNeeded()
}, completion: nil)
}
this is the result

Probably you can check your #properties and replace weak with strong. Reason is, isActive = false will set self.yourConstraint = nil, hence you wouldn't be able to use self.yourConstraint again.

Related

add 2 image views to a uiscrollview func every time it is called

My swift code below goal is to add 2 image views every time. Ass you can in the gif below only one image view is being added. I just need to add 2 image views. The image views are lastImage and lastImage2. you can see only lastImage is being shown. It seems I can only add 1 imageview when func didclickadd is called.
import UIKit
class ViewController: UIViewController {
fileprivate var lastImage:UIImageView?
fileprivate var lastImage2:UIImageView?
fileprivate var mainViewBootom:NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupVIew()
}
override func viewDidAppear(_ animated: Bool) {
scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
view.layoutIfNeeded()
}
//MARK: Components
let scrollView:UIScrollView = {
let sv = UIScrollView(frame: .zero)
return sv
}()
let mainView:UIView = {
let uv = UIView()
uv.backgroundColor = .white
return uv
}()
let btnAdd:UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Add", for: .normal)
return btn
}()
let textField:UITextField = {
let jake = UITextField()
return jake
}()
//MARK: Setup UI
func setupVIew() {
view.addSubview(scrollView)
view.addSubview(btnAdd)
view.addSubview(textField)
scrollView.translatesAutoresizingMaskIntoConstraints = false
btnAdd.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
btnAdd.centerXAnchor.constraint(equalTo: view.centerXAnchor),
btnAdd.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
btnAdd.widthAnchor.constraint(equalToConstant: 100),
btnAdd.heightAnchor.constraint(equalToConstant: 45),
//
textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 25),
textField.widthAnchor.constraint(equalToConstant: 100),
textField.heightAnchor.constraint(equalToConstant: 45),
//
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: btnAdd.topAnchor , constant: -12),
])
btnAdd.addTarget(self, action: #selector(didClickedAdd), for: .touchUpInside)
scrollView.addSubview(mainView)
mainView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
mainView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
mainView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
mainView.topAnchor.constraint(equalTo: scrollView.topAnchor),
])
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
imgView.backgroundColor = .red
mainView.addSubview(imgView)
let samsam = UIImageView(frame: CGRect(x: 0, y: 200, width: 40, height: 100))
samsam.backgroundColor = .blue
mainView.addSubview(samsam)
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imgView.widthAnchor.constraint(equalToConstant: 150).isActive = true
imgView.heightAnchor.constraint(equalToConstant: 100).isActive = true
samsam.translatesAutoresizingMaskIntoConstraints = false
samsam.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
samsam.topAnchor.constraint(equalTo: imgView.bottomAnchor).isActive = true
samsam.widthAnchor.constraint(equalToConstant: 75).isActive = true
samsam.heightAnchor.constraint(equalToConstant: 100).isActive = true
if lastImage != nil {
imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 20).isActive = true
}else{
imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 12).isActive = true
}
lastImage = samsam
mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 12)
mainViewBootom!.isActive = true
}
#objc func didClickedAdd(){
let imgView = UIImageView(frame: CGRect(x: 20, y: 0, width: 30, height: 20))
imgView.backgroundColor = .orange
mainView.addSubview(imgView)
let ss = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 50))
imgView.backgroundColor = .green
mainView.addSubview(ss)
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imgView.widthAnchor.constraint(equalToConstant: 40).isActive = true
imgView.heightAnchor.constraint(equalToConstant: 60).isActive = true
ss.translatesAutoresizingMaskIntoConstraints = false
ss.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = false
ss.widthAnchor.constraint(equalToConstant: 80).isActive = true
ss.heightAnchor.constraint(equalToConstant: 90).isActive = true
if lastImage != nil {
ss.topAnchor.constraint(equalTo: imgView.topAnchor , constant: 20).isActive = true
imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 50).isActive = true
}else{
imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 10).isActive = true
ss.bottomAnchor.constraint(equalTo: imgView.bottomAnchor , constant: 25).isActive = true
}
lastImage = imgView
lastImage2 = ss
mainView.removeConstraint(mainViewBootom!)
mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage2!.bottomAnchor , constant: 40)
mainViewBootom!.isActive = true
view.layoutIfNeeded()
scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
view.layoutIfNeeded()
}
}
Couple notes...
With proper constraint setup, auto-layout handles the UIScrollView content size all by itself. No need to ever set scrollView.contentSize = ...
You have several instances of adding a subview (image view) to your mainView, which is a subview of your scroll view, but then you add constraints from that subview to your controller's view. Make sure you are constraining elements to the proper other elements.
Here's your code, with commented changes:
class BenViewController: UIViewController {
fileprivate var lastImage:UIImageView?
// 1) don't need this
// fileprivate var lastImage2:UIImageView?
fileprivate var mainViewBootom:NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupVIew()
}
// 2) don't need this
// override func viewDidAppear(_ animated: Bool) {
// scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
// view.layoutIfNeeded()
// }
//MARK: Components
let scrollView:UIScrollView = {
let sv = UIScrollView(frame: .zero)
return sv
}()
let mainView:UIView = {
let uv = UIView()
uv.backgroundColor = .white
return uv
}()
let btnAdd:UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Add", for: .normal)
return btn
}()
let textField:UITextField = {
let jake = UITextField()
return jake
}()
//MARK: Setup UI
func setupVIew() {
view.addSubview(scrollView)
view.addSubview(btnAdd)
view.addSubview(textField)
scrollView.translatesAutoresizingMaskIntoConstraints = false
btnAdd.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
btnAdd.centerXAnchor.constraint(equalTo: view.centerXAnchor),
btnAdd.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
btnAdd.widthAnchor.constraint(equalToConstant: 100),
btnAdd.heightAnchor.constraint(equalToConstant: 45),
//
textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 25),
textField.widthAnchor.constraint(equalToConstant: 100),
textField.heightAnchor.constraint(equalToConstant: 45),
//
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: btnAdd.topAnchor , constant: -12),
])
btnAdd.addTarget(self, action: #selector(didClickedAdd), for: .touchUpInside)
scrollView.addSubview(mainView)
mainView.translatesAutoresizingMaskIntoConstraints = false
// 3) change this:
// NSLayoutConstraint.activate([
// mainView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
// mainView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
// mainView.topAnchor.constraint(equalTo: scrollView.topAnchor),
// ])
//
// to this
NSLayoutConstraint.activate([
mainView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
mainView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
mainView.topAnchor.constraint(equalTo: scrollView.topAnchor),
mainView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
mainView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
])
// end of change 3)
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
imgView.backgroundColor = .red
mainView.addSubview(imgView)
let samsam = UIImageView(frame: CGRect(x: 0, y: 200, width: 40, height: 100))
samsam.backgroundColor = .blue
mainView.addSubview(samsam)
imgView.translatesAutoresizingMaskIntoConstraints = false
// 4) change view.centerXAnchor to mainView.centerXAnchor
// imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imgView.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
imgView.widthAnchor.constraint(equalToConstant: 150).isActive = true
imgView.heightAnchor.constraint(equalToConstant: 100).isActive = true
samsam.translatesAutoresizingMaskIntoConstraints = false
// 5) change view.centerXAnchor to mainView.centerXAnchor
// samsam.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
samsam.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
samsam.topAnchor.constraint(equalTo: imgView.bottomAnchor).isActive = true
samsam.widthAnchor.constraint(equalToConstant: 75).isActive = true
samsam.heightAnchor.constraint(equalToConstant: 100).isActive = true
if lastImage != nil {
imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 20).isActive = true
}else{
imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 12).isActive = true
}
lastImage = samsam
mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 12)
mainViewBootom!.isActive = true
}
#objc func didClickedAdd(){
let imgView = UIImageView(frame: CGRect(x: 20, y: 0, width: 30, height: 20))
imgView.backgroundColor = .orange
mainView.addSubview(imgView)
let ss = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 50))
// 6) typo or copy/paste mistake
// imgView.backgroundColor = .green
ss.backgroundColor = .green
mainView.addSubview(ss)
imgView.translatesAutoresizingMaskIntoConstraints = false
// 7) change view.centerXAnchor to mainView.centerXAnchor
// imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imgView.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
imgView.widthAnchor.constraint(equalToConstant: 40).isActive = true
imgView.heightAnchor.constraint(equalToConstant: 60).isActive = true
ss.translatesAutoresizingMaskIntoConstraints = false
// 8) change view.leadingAnchor to mainView.leadingAnchor
// ss.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = false
ss.leadingAnchor.constraint(equalTo: mainView.leadingAnchor).isActive = false
ss.widthAnchor.constraint(equalToConstant: 80).isActive = true
ss.heightAnchor.constraint(equalToConstant: 90).isActive = true
// 9) always need to do this ... but did you mean imgView.bottomAnchor?
ss.topAnchor.constraint(equalTo: imgView.topAnchor , constant: 20).isActive = true
if lastImage != nil {
// 9a) instead of only here
//ss.topAnchor.constraint(equalTo: imgView.topAnchor , constant: 20).isActive = true
imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 50).isActive = true
}else{
imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 10).isActive = true
}
// 10) always need to do this
// deactivate bottom constraint
mainViewBootom?.isActive = false
lastImage = ss
mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage!.bottomAnchor, constant: 40)
mainViewBootom?.isActive = true
// 11) don't need any of this
// lastImage = imgView
// lastImage2 = ss
// mainView.removeConstraint(mainViewBootom!)
//
//
// mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage2!.bottomAnchor , constant: 40)
//
//
//
//
// mainViewBootom!.isActive = true
// view.layoutIfNeeded()
//
// scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
// view.layoutIfNeeded()
}
}
Use Xcode’s “view debugger” (the button is circled in red in my screen snapshot below) and you’ll see what’s going on:
Your ss view has no background color. Note, that when you created that view, you accidentally reset the imgView background color a second time rather than setting the ss.backgroundColor.
Fix that and you’ll see your both imgView and ss:
The view debugger is your best friend when trying to diagnose issues like this. Now, obviously, the green view probably isn’t where you intended it, but you should now be able to see it and diagnose that issue very easily.
All of this having been said, a few observations:
You’re making life much harder than you need to. If you just set the constraints for the scroll view and a stack view within that scroll view, you then only need to add an arranged subview. For example:
#objc func didTapButton(_ sender: UIButton) {
stackView.addArrangedSubview(randomView())
stackView.addArrangedSubview(randomView())
}
Note, once the stack view and scroll view have been set up (see below), then you don’t need to mess around with contentSize or constraints for these subviews at all (other than the widthAnchor and heightAnchor). The auto layout engine, combined with the constraints between the stack view and the scroll view, will take care of everything for you.
So, a full working example:
class ViewController: UIViewController {
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
let stackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.alignment = .center
stackView.spacing = 10
return stackView
}()
let button: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Add", for: .normal)
button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
configure()
}
}
// MARK: - Actions
extension ViewController {
#objc func didTapButton(_ sender: UIButton) {
stackView.addArrangedSubview(randomView())
stackView.addArrangedSubview(randomView())
}
}
// MARK: - Private utility methods
private extension ViewController {
func configure() {
view.addSubview(scrollView)
view.addSubview(button)
scrollView.addSubview(stackView)
NSLayoutConstraint.activate([
// define frame of `scrollView`
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: button.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
// define frame of `button`
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.bottomAnchor.constraint(equalTo: view.bottomAnchor),
// define contentSize of `scrollView` based upon size of `stackView`
stackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
// but define width of `stackView` relative to the _main view_
stackView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
])
button.setContentHuggingPriority(.required, for: .vertical)
}
func randomView() -> UIView {
let widthRange = view.bounds.width * 0.1 ... view.bounds.width * 0.9
let heightRange = view.bounds.width * 0.1 ... view.bounds.width * 0.25
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.widthAnchor.constraint(equalToConstant: .random(in: widthRange)),
view.heightAnchor.constraint(equalToConstant: .random(in: heightRange))
])
view.backgroundColor = UIColor(red: .random(in: 0.25...1), green: .random(in: 0.25...1), blue: .random(in: 0.25...1), alpha: 1)
return view
}
}
Even better, I’d personally set up the scroll view, stack view, button, and all the associated constraints in Interface Builder, and then that hairy configure method in my example goes away completely. It’s fun to learn how to create views programmatically, but in real-world projects, it’s rarely the most productive way to do it. Do programmatic views where needed (e.g. adding arranged subviews to the stack view on the click of a button), but otherwise, for those views that should be there when you first run the app, Interface Builder is worth considering.
E.g. It dramatically reduces the amount of code above, leaving us simply with:
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var stackView: UIStackView!
#IBAction func didTapButton(_ sender: UIButton) {
stackView.addArrangedSubview(randomView())
stackView.addArrangedSubview(randomView())
}
}
// MARK: - Private utility methods
private extension ViewController {
func randomView() -> UIView { ... }
}
Clearly, it takes a while to get used to designing views and configuring constraints in IB, but it’s worth the effort. It distills our code down the the bare essentials.
In your code, you’re setting frames for these image views and then setting translatesAutoresizingMaskIntoConstraints. There’s absolutely no point in setting the frame in that case, because translatesAutoresizingMaskIntoConstraints says “ignore my frame, use constraints instead.”
I’m assuming you’re doing all of this just to become familiar with scroll views, but it’s worth noting that, especially when adding lots of image views, that the scroll view is an inherently inefficient approach.
For example, let’s say you’ve added 100 image views, but you can see only 8 at a time. Do you really want to hold all 100 image views in memory at the same time? No.
But, UITableView, which is a subclass of UIScrollView, takes care of this. You end up only keeping the currently visible image views in memory. It’s a far better approach.
This is especially true when you start using actual UIImage objects, because they require a lot of memory. We get lulled into a sense of security, looking at reasonably sized PNG/JPG assets, but when they’re loaded into memory, they’re uncompressed and require a disproportionate amount of memory.

Scroll View is moving horizontally and not vertically

I have created a scroll view and I have tried many different methods as you can see below, however I always get the same outcome where the scroll view moves horizontally. I want it to move vertically, but it is not. Also, the text view shows the entire message in one line and does not use multiple lines as was happening before I added the scroll view.
import UIKit
import SafariServices
class MainView: UIViewController {
let transition = MainDropMenuAnimation()
let scrollView = UIScrollView()
let scrollViewView = UIView()
let factView = QuickFact()
let socialMediaSV = SocialMediaSV()
let logo = UIImageView()
let aboutUs = UITextView()
let dropMenuButton = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(patternImage: #imageLiteral(resourceName: "HomeBackground"))
addQuickFactView()
setupScrollView()
setupNavBar()
}
func setupNavBar() {
navigationItem.title = "Home"
navigationController?.navigationBar.barTintColor = .clear
dropMenuButton.setImage(#imageLiteral(resourceName: "dropMenuButton"), for: .normal)
dropMenuButton.addTarget(self, action: #selector(handleDropMenu), for: .touchUpInside)
dropMenuButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
dropMenuButton.widthAnchor.constraint(equalTo: dropMenuButton.heightAnchor).isActive = true
let leftButton = UIBarButtonItem(customView: dropMenuButton)
self.navigationItem.leftBarButtonItem = leftButton
}
#objc func handleDropMenu() {
let dropMenu = DropViewContainer()
dropMenu.modalPresentationStyle = .overCurrentContext
dropMenu.transitioningDelegate = self
present(dropMenu, animated: true)
}
func addQuickFactView() {
addChild(factView)
view.addSubview(factView.view)
factView.didMove(toParent: self)
factView.view.translatesAutoresizingMaskIntoConstraints = false
factView.view.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
factView.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
factView.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
factView.view.heightAnchor.constraint(equalToConstant: 200).isActive = true
}
func setupScrollView() {
setupView()
scrollView.contentSize.height = 3000
view.addSubview(scrollView)
positionScrollView()
}
func positionScrollView() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: factView.view.bottomAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func setupView() {
setupLogo()
setupAboutUs()
setupSocialMediaSV()
scrollView.addSubview(scrollViewView)
positionView()
}
func positionView() {
scrollViewView.translatesAutoresizingMaskIntoConstraints = false
scrollViewView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
scrollViewView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
scrollViewView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
scrollViewView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
func setupLogo() {
logo.image = #imageLiteral(resourceName: "Logo")
scrollViewView.addSubview(logo)
positionLogo()
}
func positionLogo() {
logo.translatesAutoresizingMaskIntoConstraints = false
logo.widthAnchor.constraint(equalToConstant: 200).isActive = true
logo.heightAnchor.constraint(equalToConstant: 200).isActive = true
logo.centerXAnchor.constraint(equalTo: scrollViewView.centerXAnchor).isActive = true
logo.topAnchor.constraint(equalTo: scrollViewView.topAnchor, constant: 20).isActive = true
}
func setupAboutUs() {
let aboutUsText = (NSMutableAttributedString(string: "About Us\n", attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 25)]))
aboutUsText.append(NSMutableAttributedString(string: "At Cleaner Together, we are commited to promoting recycling, reusing, and reducing (and of course composting), while spreading sanitization and cleanliness around the world. At the moment, we are just encouraging proper waste disposal, however with proper funding we have many projects we hope to accomplish.", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17), NSAttributedString.Key.foregroundColor: UIColor.black]))
aboutUs.attributedText = aboutUsText
aboutUs.textColor = .black
aboutUs.textAlignment = .left
aboutUs.isScrollEnabled = false
aboutUs.isEditable = false
aboutUs.backgroundColor = .init(white: 1.0, alpha: 0.5)
aboutUs.layer.cornerRadius = 20
scrollViewView.addSubview(aboutUs)
positionAboutUs()
}
func positionAboutUs() {
aboutUs.translatesAutoresizingMaskIntoConstraints = false
aboutUs.rightAnchor.constraint(equalTo: scrollViewView.rightAnchor, constant: -20).isActive = true
aboutUs.leftAnchor.constraint(equalTo: scrollViewView.leftAnchor, constant: 20).isActive = true
aboutUs.heightAnchor.constraint(equalToConstant: 200).isActive = true
aboutUs.topAnchor.constraint(equalTo: logo.bottomAnchor, constant: 20).isActive = true
}
func setupSocialMediaSV() {
addChild(socialMediaSV)
scrollViewView.addSubview(socialMediaSV.view)
socialMediaSV.didMove(toParent: self)
socialMediaSV.view.translatesAutoresizingMaskIntoConstraints = false
socialMediaSV.view.centerXAnchor.constraint(equalTo: scrollViewView.centerXAnchor).isActive = true
socialMediaSV.view.widthAnchor.constraint(equalToConstant: 240).isActive = true
socialMediaSV.view.topAnchor.constraint(equalTo: aboutUs.bottomAnchor, constant: 20).isActive = true
socialMediaSV.view.heightAnchor.constraint(equalToConstant: 40).isActive = true
}
}
extension MainView: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.isPresenting = true
return transition
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.isPresenting = false
return transition
}
}
You should check your constraints and make sure that your scroll view has correct contentSize.
Make scrollViewView left and right anchors also equalTo viewController's view. In func positionView()

Button is showing on screen but textField is not appearing every time. what is the error in my code?

I am setting textfied and a button programmatically. The button is showing when we run the code but not textfield. is there any problem with constraints or any other please help.
let submitButton: UIButton = {
let btn = UIButton(type:.system)
btn.backgroundColor = .blue
btn.setTitle("Login", for: .normal)
btn.tintColor = .white
btn.layer.cornerRadius = 5
btn.clipsToBounds = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let textBox: UITextView = {
let textView = UITextView()
textView.text = "we are learning iOs"
textView.font = UIFont.boldSystemFont(ofSize: 18)
textView.textAlignment = .center
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textBox)
setupTexBoxLayout()
view.addSubview(submitButton)
setupSubmitBUttonLayout()
}
private func setupTexBoxLayout(){
textBox.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
textBox.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
textBox.widthAnchor.constraint(equalToConstant: 100).isActive = true
}
private func setupSubmitBUttonLayout(){
submitButton.topAnchor.constraint(equalTo: textBox.bottomAnchor, constant: 100).isActive = true
submitButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 100).isActive = true
}
}
I have checked your code and debug it.
You have not specified height for textview so it is not showing it.
You can check the below code. I have added height constraint to it and it is displaying your textfield.
If you do not specify a height for textfield then it will take 0 height by default.
private func setupTexBoxLayout(){
textBox.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
textBox.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
textBox.widthAnchor.constraint(equalToConstant: 300).isActive = true
textBox.heightAnchor.constraint(equalToConstant: 40).isActive = true
}

Cannot see Buttons in UIScrollView

I was making a list in the form of scrollview in swift where the view consists of various types such as labels, button etc.
However when i added the button to the subview, they were not displayed although all other labels etc were displayed. I also tried messing around in the constraints and anchors.
On the other hand when i added the same button to self.view.addsubview instead of scrollview.addsubview, they were displayed just not scrolling since not a part of the scrollview anymore.
I even removed the label to make sure that the buttons were not being overlapped(didn't work either)
I also tried to see the code in "code debug hierarchy " (3D mode), i couldn't see the button there either even though i had added it
Below is my code with an example of label, scrollview and button. It be great if anyone could provide any insights.....thanks either way....
................scrollview..........................
var editInfoView : UIScrollView = {
let view = UIScrollView()
view.translatesAutoresizingMaskIntoConstraints = false
view.contentSize.height = 700
view.backgroundColor = tableBackGroundColor
view.frame = CGRect(x: 0, y: 220, width: 375, height: 400)
return view
}()
.......................label...................
vehicleNumberLabel.translatesAutoresizingMaskIntoConstraints = false
vehicleNumberLabel.textColor = .white
vehicleNumberLabel.text = "Vehicle Number"
vehicleNumberLabel.textAlignment = .left
editInfoView.addSubview(vehicleNumberLabel)
vehicleNumberLabel.leftAnchor.constraint(equalTo: editInfoView.leftAnchor).isActive = true
vehicleNumberLabel.topAnchor.constraint(equalTo: editInfoView.topAnchor, constant: 100).isActive = true
vehicleNumberLabel.widthAnchor.constraint(equalToConstant: 160).isActive = true
vehicleNumberLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
.....................button................................
vehicleNumberButton.translatesAutoresizingMaskIntoConstraints = false
vehicleNumberButton.setTitleColor(tableTextColor, for: .normal)
vehicleNumberButton.setTitle("Vehicle Number", for: .normal)
vehicleNumberButton.tintColor = tableTextColor
vehicleNumberButton.backgroundColor = tableTextColor
editInfoView.addSubview(vehicleNumberButton)
vehicleNumberButton.rightAnchor.constraint(equalTo: editInfoView.rightAnchor).isActive = true
vehicleNumberButton.topAnchor.constraint(equalTo: editInfoView.topAnchor, constant: 400).isActive = true
vehicleNumberButton.widthAnchor.constraint(equalToConstant: 600).isActive = true
vehicleNumberButton.heightAnchor.constraint(equalToConstant: 255).isActive = true
Although I cannot determine the root cause of your issue with the code and explanation provided I suspect the frame of your UIScrollView() is zero after viewDidAppear(_:) adding subviews to a CGRect.zero can cause some strange behavior with the layout engine. When we create constraints programmatically we are creating a combination of inequalities, equalities, and priorities to restrict the view to a particular frame. If a the value of these constraint equations is incorrect it changes how your relating views appear. Its good practice to avoid the use of leftAnchor and rightAnchor as well, because views may flip direction based on language (writing direction) and user settings.
ViewController.swift
import UIKit
class ViewController: UIViewController {
var editInfoScrollView : UIScrollView = {
let view = UIScrollView()
view.translatesAutoresizingMaskIntoConstraints = false
view.isUserInteractionEnabled = true
view.alwaysBounceVertical = true
view.isScrollEnabled = true
view.contentSize.height = 700
view.backgroundColor = UIColor.red.withAlphaComponent(0.3)
// Does nothing because `translatesAutoresizingMaskIntoConstraints = false`
// Instead, set the content size after activating constraints in viewDidAppear
//view.frame = CGRect(x: 0, y: 220, width: 375, height: 400)
return view
}()
var vehicleNumberLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.black
label.text = "Vehicle Number"
label.textAlignment = .left
return label
}()
lazy var vehicleNumberButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.tag = 1
button.setTitleColor(UIColor.black, for: .normal)
button.setTitle("Go to Vehicle", for: .normal)
button.tintColor = UIColor.white
button.backgroundColor = UIColor.clear
button.layer.cornerRadius = 30 // about half of button.frame.height
button.layer.borderColor = UIColor.black.cgColor
button.layer.borderWidth = 2.0
button.layer.masksToBounds = true
button.addTarget(self, action: #selector(handelButtons(_:)), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
self.setupSubviews()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.editInfoScrollView.contentSize = CGSize(width: self.view.frame.width, height: 700.0)
}
func setupSubviews() {
self.view.addSubview(editInfoScrollView)
editInfoScrollView.addSubview(vehicleNumberLabel)
editInfoScrollView.addSubview(vehicleNumberButton)
let spacing: CGFloat = 12.0
let constraints:[NSLayoutConstraint] = [
editInfoScrollView.widthAnchor.constraint(equalTo: self.view.widthAnchor),
editInfoScrollView.heightAnchor.constraint(equalToConstant: 400.0),
editInfoScrollView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
editInfoScrollView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 220.0),
vehicleNumberLabel.leadingAnchor.constraint(equalTo: editInfoScrollView.leadingAnchor, constant: spacing),
vehicleNumberLabel.trailingAnchor.constraint(equalTo: editInfoScrollView.trailingAnchor, constant: -spacing),
vehicleNumberLabel.centerXAnchor.constraint(equalTo: editInfoScrollView.centerXAnchor, constant: -50),
vehicleNumberLabel.heightAnchor.constraint(equalToConstant: 75.0),
vehicleNumberButton.widthAnchor.constraint(equalTo: editInfoScrollView.widthAnchor, multiplier: 0.66),
vehicleNumberButton.heightAnchor.constraint(equalToConstant: 65.0),
vehicleNumberButton.topAnchor.constraint(equalTo: vehicleNumberLabel.bottomAnchor, constant: spacing),
vehicleNumberButton.centerXAnchor.constraint(equalTo: editInfoScrollView.centerXAnchor),
]
NSLayoutConstraint.activate(constraints)
}
#objc func handelButtons(_ sender: UIButton) {
switch sender.tag {
case 0:
print("Default button tag")
case 1:
print("vehicleNumberButton was tapped")
default:
print("Nothing here yet")
}
}
}

Swift 3 - Constrain Button Width

I am wanting to create a simple bar at the top of my view, with two buttons side by side, taking up 50% each.
I have created the bar like so:
let topTabView = UIView()
topTabView.backgroundColor = UIColor.red
topTabView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(topTabView)
topTabView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
topTabView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
topTabView.heightAnchor.constraint(equalToConstant: 60).isActive = true
topTabView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
And this works.
I then add my two buttons, and I get all the constraints right, except I'm not sure how to get the width anchor to work, so that each button takes up 50% of the view.
let filterButton = UIButton()
filterButton.backgroundColor = UIColor.red
filterButton.setTitle("Filter", for: .normal)
filterButton.translatesAutoresizingMaskIntoConstraints = false
topTabView.addSubview(filterButton)
filterButton.leftAnchor.constraint(equalTo: topTabView.leftAnchor).isActive = true
filterButton.centerYAnchor.constraint(equalTo: topTabView.centerYAnchor).isActive = true
filterButton.heightAnchor.constraint(equalTo: topTabView.heightAnchor).isActive = true
// NOT SURE ABOUT THIS ONE
filterButton.widthAnchor.constraint(equalToConstant: 200).isActive = true
let mapButton = UIButton()
mapButton.backgroundColor = UIColor.red
mapButton.setTitle("Map", for: .normal)
mapButton.translatesAutoresizingMaskIntoConstraints = false
topTabView.addSubview(mapButton)
mapButton.rightAnchor.constraint(equalTo: topTabView.rightAnchor).isActive = true
mapButton.centerYAnchor.constraint(equalTo: topTabView.centerYAnchor).isActive = true
mapButton.heightAnchor.constraint(equalTo: topTabView.heightAnchor).isActive = true
// NOT SURE ABOUT THIS ONE
mapButton.widthAnchor.constraint(equalToConstant: 200).isActive = true
I tried something like this but it didn't work:
mapButton.widthAnchor.constraint(equalToConstant: toTabView.frame.width / 2.0).isActive = true
Any help would be amazing!
so that each button takes up 50% of the view
That is what the multiplier is for. You aren't using it. Use it!
So, you want a constraint where a button's width is the same as the superview's width except with a 0.5 value for its multiplier.
Example:
let b1 = UIButton()
b1.translatesAutoresizingMaskIntoConstraints = false
b1.backgroundColor = .green
b1.setTitle("Button1", for: .normal)
b1.setTitleColor(.black, for: .normal)
let b2 = UIButton()
b2.translatesAutoresizingMaskIntoConstraints = false
b2.backgroundColor = .yellow
b2.setTitle("Button2", for: .normal)
b2.setTitleColor(.black, for: .normal)
self.view.addSubview(b1)
self.view.addSubview(b2)
NSLayoutConstraint.activate([
b1.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50),
b2.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50),
b1.leadingAnchor.constraint(equalTo:self.view.leadingAnchor),
b2.leadingAnchor.constraint(equalTo:b1.trailingAnchor),
b1.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.5),
b2.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.5),
])
Result: