UIButton inside a UIView subclass is not working, Swift - ios

I've seen similar SO questions, the most promising ones advised to set .isUserInteractionEnabled = true and .bringSubview(toFront: subView) however both these don't seem to work in my case (not sure if I am using it correctly). I am neither able to set the backgroundColor and border for the view.
Please advise where I am going wrong.
I would like to call a function on click of a editButton which is inside a subview.
This is what I get when I run the code:
Here is the code:
class ProfilePhotoView: UIView{
var profileImage = UIImageView()
var editButton = UIButton()
var currentViewController : UIViewController
init(frame: CGRect, viewController : UIViewController){
self.currentViewController = viewController
super.init(frame: frame)
self.isUserInteractionEnabled = true
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(){
profileImage.image = #imageLiteral(resourceName: "profilePlaceHolder")
editButton.setTitle("edit", for: .normal)
editButton.setTitleColor(Colors.curieBlue, for: .normal)
editButton.isUserInteractionEnabled = true
editButton.addTarget(self, action: #selector(editPhoto), for: .touchUpInside)
profileImage.translatesAutoresizingMaskIntoConstraints = false
editButton.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(profileImage)
self.addSubview(editButton)
let viewsDict = [ "profileImage" : profileImage,
"editButton" : editButton
] as [String : Any]
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[profileImage]", options: [], metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[profileImage]", options: [], metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[editButton]", options: [], metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[profileImage]-10-[editButton]", options: [], metrics: nil, views: viewsDict))
}
func editPhoto(){
Utils.showSimpleAlertOnVC(targetVC: currentViewController, title: "Edit Button Clicked", message: "")
}
}
ViewController using ProfilePhotoView
class ProfilePhotoViewVC: UIViewController {
var profilePhotoView : ProfilePhotoView!
//let imagePickerController = UIImagePickerController() // Initializing imagePicker
//var imagePickerDelegate = ProfilePhotoDelegate()
override func viewDidLoad() {
super.viewDidLoad()
let profilePhotoFrame = CGRect(x: 0, y: 0, width: 300, height: 800)
profilePhotoView = ProfilePhotoView(frame: profilePhotoFrame, viewController: self)
profilePhotoView.isOpaque = false
profilePhotoView.backgroundColor = Colors.lightGrey
profilePhotoView.layer.borderWidth = 1
profilePhotoView.layer.borderColor = Colors.iOSBlue.cgColor
profilePhotoView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(profilePhotoView)
view.bringSubview(toFront: profilePhotoView)
view.isUserInteractionEnabled = true
let viewsDict = [ "profilePhotoView" : profilePhotoView] as [String : Any]
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[profilePhotoView]", options: [], metrics: nil, views: viewsDict))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[profilePhotoView]", options: [], metrics: nil, views: viewsDict))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

As soon as you set this:
profilePhotoView.translatesAutoresizingMaskIntoConstraints = false
your profilePhotoView's width and height get set to 0, and you need to specify them with constraints. Add (==300) and (==800) to your visual formats to set them:
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[profilePhotoView(==300)]", options: [], metrics: nil, views: viewsDict))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[profilePhotoView(==800)]", options: [], metrics: nil, views: viewsDict))
Also, consider using NSLayoutConstraint.activate() to activate the constraints instead of adding them to the view. iOS will add the constraints to the correct views for you. Also, options has a default value of [], so you can leave that off:
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
withVisualFormat: "H:|-10-[profilePhotoView(==300)]",
metrics: nil, views: viewsDict)
)
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
withVisualFormat: "V:|-10-[profilePhotoView(==800)]",
metrics: nil, views: viewsDict)
)

Related

Scroll View not working iOS Swift

Below is the code where I am trying to set scroll view to my view controller. Could someone please suggest why I am unable to scroll down the view.
I have a most part of my day trying to resolve this. Any help would be greatly appreciated.
import UIKit
class ScrollViewTestVC: UIViewController {
// FOR SCREEN DIMENSIONS
let screenSize : CGRect = UIScreen.main.bounds
var screenWidth : CGFloat
var screenHeight : CGFloat
var scrollView = UIScrollView()
var contentView = UIView()
required init?(coder aDecoder: NSCoder) {
screenHeight = screenSize.height
screenWidth = screenSize.width
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
// Setting scroll view size
scrollView = UIScrollView(frame: view.bounds)
scrollView.isScrollEnabled = true
let firstName : UILabel = {
let label = UILabel()
label.text = "First Name"
return label
}()
let lastName : UILabel = {
let label = UILabel()
label.text = "Last Name"
return label
}()
let age : UILabel = {
let label = UILabel()
label.text = "Age"
return label
}()
let weight : UILabel = {
let label = UILabel()
label.text = "Weight"
return label
}()
let gender : UILabel = {
let label = UILabel()
label.text = "Gender"
return label
}()
// TEXT FIELDS
let firstNameText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter first name"
return tf
}()
let lastNameText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter last name"
return tf
}()
let ageText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter Age"
return tf
}()
let weightText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter weight"
return tf
}()
let genderText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter Gender"
return tf
}()
// ADDING SUB VIEWS
contentView.addSubview(firstName)
contentView.addSubview(lastName)
contentView.addSubview(age)
contentView.addSubview(weight)
contentView.addSubview(gender)
contentView.addSubview(firstNameText)
contentView.addSubview(lastNameText)
contentView.addSubview(ageText)
contentView.addSubview(weightText)
contentView.addSubview(genderText)
// Adding the content view to the scroll view
scrollView.addSubview(contentView)
//self.view.addSubview(contentView)
// Pinning the contentView to the scrollView
pinView(contentView, to: scrollView)
// Adding scroll view to the main view
self.view.addSubview(scrollView)
// Removing default constraints
firstName.translatesAutoresizingMaskIntoConstraints = false
lastName.translatesAutoresizingMaskIntoConstraints = false
age.translatesAutoresizingMaskIntoConstraints = false
weight.translatesAutoresizingMaskIntoConstraints = false
gender.translatesAutoresizingMaskIntoConstraints = false
firstNameText.translatesAutoresizingMaskIntoConstraints = false
lastNameText.translatesAutoresizingMaskIntoConstraints = false
ageText.translatesAutoresizingMaskIntoConstraints = false
weightText.translatesAutoresizingMaskIntoConstraints = false
genderText.translatesAutoresizingMaskIntoConstraints = false
// Views Dict
var viewsDict = [
"firstName" : firstName,
"lastName" : lastName,
"age" : age,
"weight" : weight,
"gender" : gender,
"firstNameText" : firstNameText,
"lastNameText" : lastNameText,
"ageText" : ageText,
"weightText" : weightText,
"genderText" : genderText
]
// Do any additional setup after loading the view.
// SETTING CONSTRAINTS
var space = 100
var edgeSpace = 10
// First Name
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[firstName]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[firstName]", options: [], metrics: nil, views: viewsDict))
// First Name Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[firstName]-5-[firstNameText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[firstNameText]|", options: [], metrics: nil, views: viewsDict))
// Last Name
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[firstNameText]-\(space)-[lastName]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[lastName]", options: [], metrics: nil, views: viewsDict))
// Last Name Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[lastName]-5-[lastNameText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[lastNameText]|", options: [], metrics: nil, views: viewsDict))
// Age
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[lastNameText]-\(space)-[age]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[age]", options: [], metrics: nil, views: viewsDict))
// Age Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[age]-5-[ageText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[ageText]|", options: [], metrics: nil, views: viewsDict))
// Weight
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[ageText]-\(space)-[weight]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[weight]", options: [], metrics: nil, views: viewsDict))
// Weight Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[weight]-5-[weightText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[weightText]|", options: [], metrics: nil, views: viewsDict))
// Gender
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[weightText]-\(space)-[gender]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[gender]", options: [], metrics: nil, views: viewsDict))
// Gender Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[gender]-5-[genderText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[genderText]|", options: [], metrics: nil, views: viewsDict))
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
// The below function is used to pin one view to another view
public func pinView(_ view: UIView, to scrollView: UIScrollView) {
view.translatesAutoresizingMaskIntoConstraints = false
view.pin(to: scrollView)
}
public func pin(to view: UIView) {
NSLayoutConstraint.activate([
leadingAnchor.constraint(equalTo: view.leadingAnchor),
trailingAnchor.constraint(equalTo: view.trailingAnchor),
topAnchor.constraint(equalTo: view.topAnchor),
bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}
Your bottommost item needs to be connected to the superview so that the scrollview can compute its height. Add "|":
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[gender]-5-[genderText]|", options: [], metrics: nil, views: viewsDict))
You have to set the content size of scrollview.
See documentation

I want to add list of buttons in the same line in Swift 3.0

What I want is to add list of buttons (the number come from the service) to a uiview programmatically, so I think is I have to check if the space between the last button and the end of UIView is enough to add button or I have to go to the next line? Right?
Could you please help me on that?
Thanks,
Here you go. Button added with auto layout constraints so it will work the same in all size classes :)
var lastButton : UIButton? = nil
for i in 0...5 {
let button = UIButton()
button.backgroundColor = UIColor.green
button.setTitle("Button \(i)", for: .normal)
button.sizeToFit()
button.translatesAutoresizingMaskIntoConstraints = false
if i == 0 {
let viewComponents : [String : Any] = ["button" : button]
self.view.addSubview(button)
let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(20)-[button]", options: [], metrics: nil, views: viewComponents)
let verticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(8)-[button]", options: [], metrics: nil, views: viewComponents)
self.view.addConstraints(horizontalConstraint)
self.view.addConstraints(verticalConstraint)
self.view.layoutIfNeeded()
lastButton = button
}
else {
if (lastButton != nil) {
self.view.addSubview(button)
let viewComponents : [String : Any] = ["button" : button, "lastButton" : lastButton!]
if (lastButton!.frame.maxX + 8 + button.bounds.size.width) > self.view.bounds.size.width {
let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "|-(8)-[button]", options: [], metrics: nil, views: viewComponents)
let verticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:[lastButton]-(8)-[button]", options: [], metrics: nil, views: viewComponents)
self.view.addConstraints(horizontalConstraint)
self.view.addConstraints(verticalConstraint)
self.view.layoutIfNeeded()
lastButton = button
}
else {
self.view.addSubview(button)
let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "[lastButton]-(8)-[button]", options: [.alignAllTop], metrics: nil, views: viewComponents)
self.view.addConstraints(horizontalConstraint)
self.view.layoutIfNeeded()
lastButton = button
}
}
}
}
The idea is using UICollectionView. You can implement it with following:
Subclass UICollectionViewCell to make your own cell which has the button
Subclass UICollectionViewFlowLayout, override
layoutAttributesForItem(at indexPath: IndexPath) which provides the attributes for each cell. You may need to pre-calculate the frame of button or cell in function prepare()
Create UICollectionView instance with the collectionviewLayout you just subclassed.

subview not showing in scrollview when using visual format constraint

I cannot understand why the blue view is not showing please take a look at my code. When i use view.addSubView(mapView) its shows in the main view but when I do scrollView.addSubView(mapView) it does not show.Everything appear to be correct with the constraint. I not sure why its not working.
import UIKit
class practiceViewController: UIViewController,UIScrollViewDelegate {
override func viewDidLoad() {
var allConstraint = [NSLayoutConstraint]()
let scrollView:UIScrollView = {
let v = UIScrollView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let mapView:UIView = {
let v = UIView()
v.backgroundColor = .blue
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
//views
let views = [
"scrollView":scrollView,
"mapView":mapView
]
//add views
view.addSubview(scrollView)
scrollView.addSubview(mapView)
// constraints
let scrollviewHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: [], metrics: nil, views: views)
let scrollviewVerticleConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView]|", options: [], metrics: nil, views: views)
allConstraint += scrollviewVerticleConstraint
allConstraint += scrollviewHorizontalConstraint
let mapViewHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|[mapView]|", options: [], metrics: nil, views: views)
let mapViewVerticleConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[mapView]|", options: [], metrics: nil, views: views)
allConstraint += mapViewHorizontalConstraint
allConstraint += mapViewVerticleConstraint
NSLayoutConstraint.activate(allConstraint)
}
}
Your mapView needs a width and height. The scroll view doesn't know what the content size is until you set the size of your content so the scrollview defaults to zero. Try something like this instead:
let mapViewHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|[mapView(200)]|", options: [], metrics: nil, views: views)
let mapViewVerticleConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[mapView(200)]|", options: [], metrics: nil, views: views)

AutoLayout constraints for programmatically added buttons in a scrollView

I'm struggling with making autolayout work for a horizontal scrollview populated with an unknown number of buttons (in this case the number is stored in sceneCount).
I've tried to approach the problem in other ways as well, but this seems to be the closest I could get to a result (no contradictory constraints). Unfortunately I only get a white screen at runtime with no errors.
This is how I wish my scrollView would look like.
Hope you guys can spot the problem!
import UIKit
class ViewController: UIViewController {
let sceneCount = 4
var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
var buttons: [UIButton] = [UIButton]()
func makeLayout(){
//Make the content view
let view1 = UIScrollView()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
view1.backgroundColor = UIColor.redColor()
//Make the scroll view
let view2 = UIScrollView()
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view2.backgroundColor = UIColor(red: 0.75, green: 0.75, blue: 0.1, alpha: 1.0)
view.addSubview(view1)
view2.addSubview(view1)
//Create the buttons
for i in 0...(sceneCount-1) {
button.setTranslatesAutoresizingMaskIntoConstraints(false)
button.addTarget(self, action: Selector("scene\(i)Pressed"), forControlEvents: UIControlEvents.TouchUpInside)
button.setBackgroundImage(UIImage(named: "Scene\(i+1)"), forState: UIControlState.Normal)
button.sizeThatFits(CGSizeMake(40, 40))
buttons.append(button)
view1.addSubview(button)
}
//set horizontal spacing between the buttons
for i in 1...(sceneCount-2) {
var button1 = UIButton.buttonWithType(UIButtonType.System) as! UIButton
var button2 = UIButton.buttonWithType(UIButtonType.System) as! UIButton
button1 = buttons[i - 1]
button2 = buttons[i]
var dictionary1 = [String: UIButton]()
dictionary1.updateValue(button1, forKey: "scene1")
dictionary1.updateValue(button2, forKey: "scene2")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[scene1]-[scene2]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary1) as [AnyObject])
}
//set vertical spacing for all buttons
for i in 0...(sceneCount-1) {
var button1 = UIButton.buttonWithType(UIButtonType.System) as! UIButton
button1 = buttons[i]
var dictionary2 = [String: UIButton]()
dictionary2.updateValue(button1, forKey: "button1")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[button1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary2) as [AnyObject])
}
//set horizontal distance to container for first button
if sceneCount > 0 {
var buttonFirst: UIButton = buttons[0]
var dictionary3 = [String: UIButton]()
dictionary3.updateValue(buttonFirst, forKey: "buttonFirst")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[buttonFirst]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary3) as [AnyObject])
}
//set horizontal distance to container for last button
if sceneCount > 0 {
var buttonLast: UIButton = buttons[sceneCount-1]
var dictionary4 = [String: UIButton]()
dictionary4.updateValue(buttonLast, forKey: "buttonLast")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[buttonLast]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary4) as [AnyObject])
}
}
override func viewDidLoad() {
super.viewDidLoad()
makeLayout()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I managed to make your code work with three major changes as follows:
1 - Your content view needs to be of type UIView
let view1 = UIView()
This view will hold a UIScrollView (view2) and they have to have their constraints set. On view1 you will be able to set the size of the scroll view, that's why I made view 2 with 0 distance from the super view.
view1.addSubview(view2)
var dictionary = [String: UIView]()
dictionary.updateValue(view1, forKey: "view1")
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
dictionary = [String: UIView]()
dictionary.updateValue(view2, forKey: "view2")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
2 - As you were using the same reference to create new buttons, the final array would have the same button in every position.
I moved the initialization of each button inside the for that creates buttons.
var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
view2.addSubview(button)
3- After that I just updated your constraints to be inserted between the buttons and the scroll view (view2).
And here is the final code:
import UIKit
class ViewController: UIViewController {
let sceneCount = 4
var buttons: [UIButton] = [UIButton]()
func makeLayout(){
//Make the content view
let view1 = UIView()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
view1.backgroundColor = UIColor.redColor()
//Make the scroll view
let view2 = UIScrollView()
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view2.backgroundColor = UIColor(red: 0.75, green: 0.75, blue: 0.1, alpha: 1.0)
view.addSubview(view1)
view1.addSubview(view2)
var dictionary = [String: UIView]()
dictionary.updateValue(view1, forKey: "view1")
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
dictionary = [String: UIView]()
dictionary.updateValue(view2, forKey: "view2")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
//Create the buttons
for i in 0...(sceneCount-1) {
var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
button.setTranslatesAutoresizingMaskIntoConstraints(false)
button.addTarget(self, action: Selector("scene\(i)Pressed"), forControlEvents: UIControlEvents.TouchUpInside)
button.setBackgroundImage(UIImage(named: "Scene\(i+1)"), forState: UIControlState.Normal)
button.sizeThatFits(CGSizeMake(40, 40))
buttons.append(button)
view2.addSubview(button)
}
//set vertical spacing for all buttons
for i in 0...(sceneCount-1) {
var button1 = buttons[i]
var dictionary2 = [String: UIButton]()
dictionary2.updateValue(button1, forKey: "button1")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[button1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary2) as [AnyObject])
}
//set horizontal distance to container for first button
if sceneCount > 0 {
var buttonFirst: UIButton = buttons[0]
var dictionary3 = [String: UIButton]()
dictionary3.updateValue(buttonFirst, forKey: "buttonFirst")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[buttonFirst]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary3) as [AnyObject])
}
//set horizontal spacing between the buttons
for i in 1...(sceneCount-1) {
var button1 = buttons[i - 1]
var button2 = buttons[i]
var dictionary1 = [String: UIButton]()
dictionary1.updateValue(button1, forKey: "scene1")
dictionary1.updateValue(button2, forKey: "scene2")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[scene1]-[scene2]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary1) as [AnyObject])
}
//set horizontal distance to container for last button
if sceneCount > 0 {
var buttonLast: UIButton = buttons[sceneCount-1]
var dictionary4 = [String: UIButton]()
dictionary4.updateValue(buttonLast, forKey: "buttonLast")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[buttonLast]-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary4) as [AnyObject])
}
}
override func viewDidLoad() {
super.viewDidLoad()
makeLayout()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Swift NSLayout uneven alignment

I am trying to mess around with autolayout programmatically in Swift. However I have one problem. I want my view1 (red box) to have a the regular spaced alignment with the superview (H:|-[view1]-|)". This works for the right alignment but not the left. I want the left side of the view to have the same spacing as the right side. The view seems to want to align itself horizontally with the button below. Does anyone know how to fix this or what I am doing wrong?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "yolo"
let frame = UIScreen.mainScreen().bounds
var b = UIButton.buttonWithType(UIButtonType.System) as! UIButton
b.frame = CGRectMake(frame.minX + 50, frame.minY + 100, frame.width * 0.8, frame.height * 0.2)
b.backgroundColor = UIColor.purpleColor()
b.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
b.layer.cornerRadius = 17
b.setTitle("hello", forState: UIControlState.Normal)
b.setTranslatesAutoresizingMaskIntoConstraints(false)
// Do any additional setup after loading the view, typically from a nib.
let view1 = UIView()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
view1.backgroundColor = UIColor.redColor()
let view2 = UIView()
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view2.backgroundColor = UIColor.yellowColor()
self.view.addSubview(b)
self.view.addSubview(view1)
// dictionary for views
let viewsDictionary = ["view1":view1,"view2":view2, "b":b]
let button_constraint_H:Array = NSLayoutConstraint.constraintsWithVisualFormat("H:[b(>=200)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
let button_constraint_V:Array = NSLayoutConstraint.constraintsWithVisualFormat("V:[b(>=200)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
b.addConstraints(button_constraint_H as [AnyObject])
b.addConstraints(button_constraint_V as [AnyObject])
//view1
let view1_constraint_H:Array = NSLayoutConstraint.constraintsWithVisualFormat("H:[view1(50)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
let view1_constraint_V:Array = NSLayoutConstraint.constraintsWithVisualFormat("V:[view1(50)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
view1.addConstraints(view1_constraint_H as [AnyObject])
view1.addConstraints(view1_constraint_V as [AnyObject])
let view_constraint_H:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("H:|-[view1]-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
let view_constraint_V:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("V:|-90-[view1]-[b]-0-|", options: NSLayoutFormatOptions.AlignAllLeading, metrics: nil, views: viewsDictionary)
let view_constraint_H2:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("H:|[b]|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
view.addConstraints(view_constraint_H2 as [AnyObject])
view.addConstraints(view_constraint_V as [AnyObject])
view.addConstraints(view_constraint_H as [AnyObject])
}
The problem is that your constraints make no sense. You are saying this:
"H:[view1(50)]"
"H:|-[view1]-|"
So on the one hand you want view1 to be aligned with the margins of its superview (this is what - means), but on the other hand you want view1 to be exactly 50 points wide (that is what (50) means). You can't have both!

Resources