how to add constraints programmatically for rangeslider? - ios

Here I used a GZRangeSlider for having a range slider and here i need to give constraints programmatically so that in order to have support for landscape mode can anyone help me how to give programmatically in table view cell ?
class SliderCell : UITableViewCell {
var rangeSlider = GZRangeSlider()
override func awakeFromNib() {
super.awakeFromNib()
rangeSlider = GZRangeSlider(frame: CGRect(x:8,y: 60 ,width: self.contentView.bounds.width - 32,height: 30))
self.addSubview(rangeSlider)
}

let rangeSliderLeadingConstraint = NSLayoutConstraint(
item: rangeSlider,
attribute: .leading,
relatedBy: .equal,
toItem: self,
attribute: .leading,
multiplier: 1.0,
constant: 0)
let rangeSliderTrailingConstriant = NSLayoutConstraint(
item: rangeSlider,
attribute: .trailing ,
relatedBy: .equal,
toItem: self,
attribute: .trailing,
multiplier: 1.0,
constant: 0)
let rangeSliderBottomConstriant = NSLayoutConstraint(
item:,
attribute: .bottom ,
relatedBy: .equal,
toItem: self,
attribute: .bottom,
multiplier: 1.0,
constant: 0)
let rangeSliderTopConstriant = NSLayoutConstraint(
item: rangeSlider,
attribute: .top ,
relatedBy: .equal,
toItem: self,
attribute: .top,
multiplier: 1.0,
constant: 0)
self.addConstraints([rangeSliderTopConstriant,rangeSliderBottomConstriant,rangeSliderTrailingConstriant,rangeSliderLeadingConstraint])

Related

NSLayoutConstraint in playground

I'm trying to reproduce a scenario like this where the red and blue rectangles can occupy same width and height (and same gap between them) for different screen sizes.
I'm using NSLayoutConstraint (I know that anchors are preferred now, just trying to explore the basics). I tried the following code in swift playground:
import Foundation
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
var firstColorView: UIView!
var secondColorView: UIView!
override func viewWillAppear(_ animated: Bool) {
var myView: UIView!
myView = view
myView.backgroundColor = .white
firstColorView = UIView()
secondColorView = UIView()
firstColorView.backgroundColor = .red
secondColorView.backgroundColor = .blue
myView.addSubview(firstColorView)
myView.addSubview(secondColorView)
//myView.translatesAutoresizingMaskIntoConstraints = false
//view.addSubview(myView)
// horizontal constraints
let left_constraint = NSLayoutConstraint(item: firstColorView, attribute: .leftMargin, relatedBy: .equal, toItem: myView, attribute: .left, multiplier: 1.0, constant: 20)
let middle_constraint = NSLayoutConstraint(item: secondColorView, attribute: .leftMargin, relatedBy: .equal, toItem: firstColorView, attribute: .right, multiplier: 1.0, constant: 10)
let right_constraint = NSLayoutConstraint(item: myView, attribute: .rightMargin, relatedBy: .equal, toItem: secondColorView, attribute: .right, multiplier: 1.0, constant: 20)
let width_constraint = NSLayoutConstraint(item: firstColorView, attribute: .width, relatedBy: .equal, toItem: secondColorView, attribute: .width, multiplier: 1.0, constant: 0)
// vertical constraints
let top_constraint1 = NSLayoutConstraint(item: firstColorView, attribute: .top, relatedBy: .equal, toItem: myView, attribute: .top, multiplier: 1.0, constant: 10)
let top_constraint2 = NSLayoutConstraint(item: secondColorView, attribute: .top, relatedBy: .equal, toItem: myView, attribute: .top, multiplier: 1.0, constant: 10)
let bottom_constraint1 = NSLayoutConstraint(item: myView, attribute: .bottom, relatedBy: .equal, toItem: firstColorView, attribute: .bottom, multiplier: 1.0, constant: 10)
let bottom_constraint2 = NSLayoutConstraint(item: myView, attribute: .bottom, relatedBy: .equal, toItem: secondColorView, attribute: .bottom, multiplier: 1.0, constant: 0)
NSLayoutConstraint.activate([left_constraint, middle_constraint, right_constraint, width_constraint, top_constraint1, top_constraint2, bottom_constraint1, bottom_constraint2])
self.view.layoutIfNeeded()
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = MyViewController()
But all it shows is a white screen, whose width doesn't match an iphone's. What am I doing wrong here? Why can't I see the red and blue screen?
You miss
firstColorView.translatesAutoresizingMaskIntoConstraints = false
secondColorView.translatesAutoresizingMaskIntoConstraints = false

Programmatically made constraints are not working

As I want to move away from xib and make my layout programmatically, I found that using the same exact constraints doesn't work as I would expect.
I want to make this UITableViewCell
It's a quite simple cell with a small icon to its right as well as an Activity Indicator so I can toggle which one I want to see. They are inside a View and to their left is a label
Those are my constraints in the outline view
And it works perfectly. However when I'm removing the XIB and doing all of the code myself, nothing works anymore
So here's my code:
class StandardRow: UITableViewCell {
private var initialWidth: CGFloat = 20
public var fetching: Bool = false {
didSet {
if (fetching) {
activityIndicator?.startAnimating()
} else {
activityIndicator?.stopAnimating()
}
changeImageWidth()
}
}
public var rightImage: UIImage? = nil {
didSet {
rightImageView?.image = rightImage
changeImageWidth()
}
}
private func changeImageWidth() {
if (activityIndicator?.isAnimating) ?? false || rightImage != nil {
imageWidth?.constant = initialWidth
} else {
imageWidth?.constant = 0
}
}
override func prepareForReuse() {
valueLabel?.text = ""
imageView?.image = nil
rightImage = nil
fetching = false
textLabel?.text = ""
accessoryType = .none
}
//Views
private var imageContainer = UIView()
private var rightImageView = UIImageView()
private var activityIndicator: UIActivityIndicatorView? = UIActivityIndicatorView()
public var valueLabel: UILabel? = UILabel()
private var imageWidth: NSLayoutConstraint? = nil
override init(style: UITableViewCell.CellStyle = .default, reuseIdentifier: String? = nil) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
buildView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
buildView()
}
func buildView() {
contentView.addSubview(valueLabel!)
imageContainer.addSubview(rightImageView)
imageContainer.addSubview(activityIndicator!)
contentView.addSubview(imageContainer)
imageContainer.backgroundColor = .red
}
override func layoutSubviews() {
super.layoutSubviews()
//IMAGE CONTAINER CONSTRAINTS
imageWidth = NSLayoutConstraint(item: imageContainer, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: initialWidth)
imageWidth?.priority = UILayoutPriority(rawValue: 999)
imageWidth?.isActive = true
let bottomImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: 0)
bottomImageContainerConstraint.isActive = true
bottomImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)
let topImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 0)
topImageContainerConstraint.isActive = true
topImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)
let trailingImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 5)
trailingImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)
trailingImageContainerConstraint.isActive = true
let centerYImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .centerY, relatedBy: .equal, toItem: contentView, attribute: .centerY, multiplier: 1, constant: 0)
centerYImageContainerConstraint.isActive = true
centerYImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)
//VALUE LABEL CONSTRAINTS
let trailingValueLabelConstraint = NSLayoutConstraint(item: valueLabel!, attribute: .trailing, relatedBy: .equal, toItem: imageContainer, attribute: .leading, multiplier: 1, constant: 5)
trailingValueLabelConstraint.isActive = true
trailingValueLabelConstraint.priority = UILayoutPriority(rawValue: 999)
let centerYValueLabelConstraint = NSLayoutConstraint(item: valueLabel!, attribute: .centerY, relatedBy: .equal, toItem: contentView, attribute: .centerY, multiplier: 1, constant: 0)
centerYValueLabelConstraint.isActive = true
centerYValueLabelConstraint.priority = UILayoutPriority(rawValue: 999)
//ACTIVITY INDICATOR CONSTRAINGS
NSLayoutConstraint(item: activityIndicator!, attribute: .trailing, relatedBy: .equal, toItem: imageContainer, attribute: .trailing, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: activityIndicator!, attribute: .leading, relatedBy: .equal, toItem: imageContainer, attribute: .leading, multiplier: 1, constant: 11).isActive = false
NSLayoutConstraint(item: activityIndicator!, attribute: .bottom, relatedBy: .equal, toItem: imageContainer, attribute: .bottom, multiplier: 1, constant: 11).isActive = false
NSLayoutConstraint(item: activityIndicator!, attribute: .top, relatedBy: .equal, toItem: imageContainer, attribute: .top, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: activityIndicator!, attribute: .centerY, relatedBy: .equal, toItem: imageContainer, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
//RIGHT IMAGE VIEW CONSTRAINTS
NSLayoutConstraint(item: rightImageView, attribute: .trailing, relatedBy: .equal, toItem: activityIndicator!, attribute: .trailing, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: rightImageView, attribute: .leading, relatedBy: .equal, toItem: rightImageView, attribute: .leading, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: rightImageView, attribute: .bottom, relatedBy: .equal, toItem: activityIndicator!, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: rightImageView, attribute: .top, relatedBy: .equal, toItem: activityIndicator!, attribute: .top, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: rightImageView, attribute: .centerY, relatedBy: .equal, toItem: activityIndicator!, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
//changeImageWidth()
}}
So I have a few ideas to where it can come from, firstly being "translatesAutoresizingMaskIntoConstraints" set to true by default, but when I'm setting it to false in the superview then my cell doesn't show anymore and in the contentView, Xcode tells me I shouldn't do that because of an undefined behaviour
I'm also using Reveal to debug my UI and then I found those peculiar values:
Which is not what I want, Reveal is reporting that those constraints are translating the autoresizing mask of the view to autolayout so it would confirm the previous theory. I did set the priority to 999 to some of the constraints because otherwise they would be broken.
I'm actually at a dead end and I think I'm missing something but I can't pinpoint what as I don't have enough experience with non-interface builder constraints
Try Anchors, it's much easier.
Example
var redView = UIView()
redView.backgroundColor = .red
anyView.addsubView(redView)
redView.translatesAutoresizingMaskIntoConstraints = false
redView.centerXAnchor.constraint(equalTo: self.parentView.centerXAnchor).isActive = true
redView.centerYAnchor.constraint(equalTo: self.parentView.centerYAnchor).isActive = true
redView.heightAnchor.constraint(equalToConstant: 100).isActive = true
redView.widthAnchor.constraint(equalToConstant: 100).isActive = true
You can add the same method to your UIView extension
func constrainToEdges(_ subview: UIView, top: CGFloat = 0, bottom: CGFloat = 0, leading: CGFloat = 0, trailing: CGFloat = 0) {
subview.translatesAutoresizingMaskIntoConstraints = false
let topContraint = NSLayoutConstraint(
item: subview,
attribute: .top,
relatedBy: .equal,
toItem: self,
attribute: .top,
multiplier: 1.0,
constant: top)
let bottomConstraint = NSLayoutConstraint(
item: subview,
attribute: .bottom,
relatedBy: .equal,
toItem: self,
attribute: .bottom,
multiplier: 1.0,
constant: bottom)
let leadingContraint = NSLayoutConstraint(
item: subview,
attribute: .leading,
relatedBy: .equal,
toItem: self,
attribute: .leading,
multiplier: 1.0,
constant: leading)
let trailingContraint = NSLayoutConstraint(
item: subview,
attribute: .trailing,
relatedBy: .equal,
toItem: self,
attribute: .trailing,
multiplier: 1.0,
constant: trailing)
addConstraints([
topContraint,
bottomConstraint,
leadingContraint,
trailingContraint])
}
I recommend using this framework for building constraint based layouts programmatically, it makes the process straightforward and faster. Take the setup for the contentView of this cell for example:
contentView.addSubview(descriptionLabel)
contentView.addSubview(amountLabel)
contentView.addSubview(dateLabel)
contentView.addSubview(bottomRightLabel)
constrain(descriptionLabel, amountLabel, dateLabel, bottomRightLabel) { desc, amount, date, bottomRight in
desc.top == desc.superview!.top + 16
desc.left == desc.superview!.left + 16
desc.right <= amount.left + 12
desc.bottom == date.top - 12
amount.centerY == desc.centerY
amount.right == amount.superview!.right - 12
date.left == date.superview!.left + 16
date.right <= bottomRight.left - 12
date.bottom == date.superview!.bottom - 16
bottomRight.centerY == date.centerY
bottomRight.right == bottomRight.superview!.right - 12
}

How to add UIButton in between two views without using storyboard?

I am unable to understand where to add subview so that the button can lie in middle of the existing views.
This is work for me. (swift 4.0)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let yourView = self.view
addButtonOnCentral(yourView!)
}
func addButtonOnCentral(_ view:UIView) {
let btn = UIButton.init()
btn.backgroundColor = UIColor.yellow
btn.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(btn)
let widthConstraint = NSLayoutConstraint(item: btn, attribute: .width, relatedBy: .equal,
toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 20)
let heightConstraint = NSLayoutConstraint(item: btn, attribute: .height, relatedBy: .equal,
toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 30)
let xConstraint = NSLayoutConstraint(item: btn, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: btn, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])
}

I need top constraint of unknow element

I have an app which is downloading image from server by clicking the button. After image have downloaded i create a new imageView and add it to the my contentView(UIView). I need to create the constraints - every new imageview need top constraint from previous one
func addNewImageToTheScrollView(img: UIImage?) {
if let imageResponse = img {
let imageView = UIImageView(image: imageResponse.crop(rect: CGRect(x: 0, y: imageResponse.size.height/2, width: self.contentView.frame.width, height: 200)))
self.contentView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
let x = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: self.contentView, attribute: .centerX, multiplier: 1.0, constant: 0)
let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 30)
let width = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: self.contentView, attribute: .width, multiplier: 1.0, constant: 0)
let height = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 150)
self.contentView.addConstraints([x, y])
imageView.addConstraints([width, height])
}
}
If i comment the constraint code, it will be work fine unless every new imageView will be on the same place, on the top of the View. Now whit this constraint code i have such code issue after downloading
2017-07-02 14:50:01.018 ImageFromServerTest[11516:1080948] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSLayoutConstraint for >: A multiplier of 0 or a nil second item together with a location for the first attribute creates an illegal constraint of a location equal to a constant. Location attributes must be specified in pairs.'
Whenever you are working with scrollViews, there are 2 thumb rules for it:-
Give the scrollView leading, trailing, bottom, and top constraint with respect to the superview, that is self.view
#IbOutlet weak var scrollView: UIScrollView!
let leading = NSLayoutConstraint(item: scrollView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leadingMargin, multiplier: 1.0, constant: 0)
let trailing = NSLayoutConstraint(item: scrollView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailingMargin, multiplier: 1.0, constant: 0)
let top = NSLayoutConstraint(item: scrollView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1.0, constant: 0)
let bottom = NSLayoutConstraint(item: scrollView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: 0)
Add constraints to the contentView with respect to the scrollView
#IbOutlet weak var contentView: UIView!
let leading = NSLayoutConstraint(item: contentView, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leading, multiplier: 1.0, constant: 0)
let trailing = NSLayoutConstraint(item: contentView, attribute: .trailing, relatedBy: .equal, toItem: scrollView, attribute: .trailing, multiplier: 1.0, constant: 0)
let top = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1.0, constant: 0)
//increase the constant according to how much long you need the scrollview to be
let bottom = NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1.0, constant: 0)
Now add your subviews constraints (labels, images) with respect to the contentView
For example- You received your first image, so we will maintain an array of UIImageViews outside your function.
var imageViews = [UIImageViews]() //declared outside the function
//received an image here
var imageView = UIImageView() // define the frame according to yourself using frame init method
imageView.image = image
if imageViews.isEmpty { // first image view
//add constraints to first image view
let x = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1.0, constant: 0)
let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1.0, constant: 30)
let width = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: self.contentView, attribute: .width, multiplier: 1.0, constant: 0)
let height = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 150)
}
else { //second, third, fourth image view... so on
let x = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1.0, constant: 0)
let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: imageViews[imageViews.count - 1], attribute: .bottom, multiplier: 1.0, constant: 30)
let width = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: self.contentView, attribute: .width, multiplier: 1.0, constant: 0)
let height = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 150)
}
imageViews.append(imageView)
}
Hope you got an idea now, how to proceed with this problem. If having more than 4 or 5 imageviews, you'll probably want to check the count of the array and increase the contentView of the scrollView accordingly. you can do so by using
self.scrollView.contentSize = CGSize(width, height)
I believe you have a problem here:
let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 30)
"toItem" parameter should have some value. Also first parameter should be imageView.topAnchor. Probably it should look something like this:
let y = NSLayoutConstraint(item: imageView.topAnchor, attribute: .top, relatedBy: .equal, toItem: self.contentView.topAnchor, attribute: .notAnAttribute, multiplier: 1.0, constant: 30)

How best to optimize NSLayoutConstraint?

Colleagues,
I develop a custom keyboard. There was a problem with the speed of switching between types of keyboards (letters, numbers, special characters). This is due to the fact that each time the button is re-drawn. NSLayoutConstraint I set up as follows:
There is a class KeyboardViewController. He adds to his KeyboardView
let left = NSLayoutConstraint(item: self.keyboardView, attribute: .Left, relatedBy: .Equal,
toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 0.0)
let top = NSLayoutConstraint(item: self.keyboardView, attribute: .Top, relatedBy: .Equal,
toItem: placeForSuggestion!, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
let right = NSLayoutConstraint(item: self.keyboardView, attribute: .Right, relatedBy: .Equal,
toItem: self.view, attribute: .Right, multiplier: 1.0, constant: 0.0)
let bottom = NSLayoutConstraint(item: self.keyboardView, attribute: .Bottom, relatedBy: .Equal,
toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
let height = NSLayoutConstraint(item: self.keyboardView, attribute: .Height, relatedBy: .Equal,
toItem: self.view, attribute: .Height, multiplier: 1.0, constant: 216)
left.priority = 999
right.priority = 999
bottom.priority = 999
top.priority = 999
height.priority = 999
self.view.addConstraints([left, right, top, bottom, height])
In the class KeyboardView, buttons are added as follows:
super.updateConstraints()
if !layoutConstrained {
var lastRowView: UIView? = nil
for (rowIndex, keyRow) in keyRows.enumerate() {
var lastKeyView: UIView? = nil
for (keyIndex, key) in keyRow.enumerate() {
var relativeWidth: CGFloat = 0.0;
switch key.type! {
case .ModeChange:
relativeWidth = 0.92/8
case .KeyboardChange:
relativeWidth = 0.92/8
case .Space:
relativeWidth = 3.92/8
case .Return:
relativeWidth = 1.84/8
default:
relativeWidth = 0.0
}
key.translatesAutoresizingMaskIntoConstraints = false
if let lastView = lastKeyView {
let left: NSLayoutConstraint!
if (key.keyCap == "Z" || (key.keyCap == "backspace" && keyRow[keyIndex - 1].keyCap == "M")) {
left = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: lastView, attribute: .Right, multiplier: 1.0, constant: englishMZSpace)
} else {
left = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: lastView, attribute: .Right, multiplier: 1.0, constant: distanceBetweenKeys)
}
let top = NSLayoutConstraint(item: key, attribute: .Top, relatedBy: .Equal,
toItem: lastView, attribute: .Top, multiplier: 1.0, constant: 0.0)
let bottom = NSLayoutConstraint(item: key, attribute: .Bottom, relatedBy: .Equal,
toItem: lastView, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
var width: NSLayoutConstraint?
if relativeWidth == 0.0 {
width = NSLayoutConstraint(item: key, attribute: .Width, relatedBy: .Equal,
toItem: lastView, attribute: .Width, multiplier: 1.0, constant: 0.0)
} else {
width = NSLayoutConstraint(item: key, attribute: .Width, relatedBy: .Equal,
toItem: self, attribute: .Width, multiplier: relativeWidth, constant: 0.0)
}
self.addConstraints([left, top, bottom, width!])
} else {
let leftEdge: NSLayoutConstraint
if key.keyCap == "A" {
leftEdge = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: self, attribute: .Left, multiplier: 1.0, constant: englishALSpace)
} else {
leftEdge = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: self, attribute: .Left, multiplier: 1.0, constant: leftRightSpace)
}
self.addConstraint(leftEdge)
if let lastRow = lastRowView {
let top = NSLayoutConstraint(item: key, attribute: .Top, relatedBy:.Equal,
toItem: lastRow, attribute: .Bottom, multiplier: 1.0, constant: rowTopInset)
let height = NSLayoutConstraint(item: key, attribute: .Height, relatedBy: .Equal,
toItem: lastRow, attribute: .Height, multiplier: 1.0, constant: 0.0)
self.addConstraints([top, height])
} else {
let topEdge = NSLayoutConstraint(item: key, attribute: .Top, relatedBy:.Equal,
toItem: self, attribute: .Top, multiplier: 1.0, constant: rowTopInset)
self.addConstraint(topEdge)
}
if rowIndex == keyRows.count - 1 {
let bottomEdge = NSLayoutConstraint(item: key, attribute: .Bottom, relatedBy: .Equal,
toItem: self, attribute: .Bottom, multiplier: 1.0, constant: -rowBottomInset)
self.addConstraint(bottomEdge)
}
lastRowView = key
}
if keyIndex == keyRow.count - 1 {
let rightEdge: NSLayoutConstraint
if key.keyCap == "L" {
rightEdge = NSLayoutConstraint(item: key, attribute: .Right, relatedBy: .Equal,
toItem: self, attribute: .Right, multiplier: 1.0, constant: -englishALSpace)
} else {
rightEdge = NSLayoutConstraint(item: key, attribute: .Right, relatedBy: .Equal,
toItem: self, attribute: .Right, multiplier: 1.0, constant: -leftRightSpace)
}
self.addConstraint(rightEdge)
}
lastKeyView = key
}
}
layoutConstrained = true
}
I see 2 variants of optimization:
After the first run to cache all NSLayoutConstraint
Use CGRectMake instead NSLayoutConstraint
You may be able to offer more relevant options?
In this video I try to switch keyboard and print quickly https://yadi.sk/i/36YxEwgtmHJVd
It seems pretty fast to me in the video.
However, instead of re-creating the layout constraints every time I would recommend to create each keyboard type once, and then just switch between the existing keyboards. Regarding the small views that shouldn't be a memory issue, and it's a lot better than recreating and deleting constraints all the time.
Alternatively, if the key amount stays (almost) the same, you could just change the constraint's values and even animate the change of key positions for a maybe nice effect.

Resources