I have a question... I am really not understand something.
I have a UIView Class which only create a UITextLabel.. I'm trying to add instances from this class to my Viewcontroller. This is how my UIViewClass look like:
class PostLineItem: UIView {
var labelText : String!
var labelHeader : String!
init(labelText: String , labelHeader: String) {
super.init(frame: CGRect.zeroRect)
self.labelText = labelText
self.labelHeader = labelHeader
let tlb = timeLineBlock()
//tlb.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addSubview(tlb)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: tlb, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Width, relatedBy: .Equal, toItem: self, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)
])
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("required public")
}
private func timeLineBlock() -> UIView{
let viewNew = UIView()
viewNew.setTranslatesAutoresizingMaskIntoConstraints(false)
let titleLabel = UILabel()
titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
titleLabel.font = UIFont(name: "ArialMT", size: 20)
titleLabel.textColor = UIColor.blackColor()
titleLabel.text = labelHeader
titleLabel.numberOfLines = 0
viewNew.addSubview(titleLabel)
titleLabel.backgroundColor = UIColor.redColor()
/* IF I NOT COMMENT THIS PART INSTANCE OF THIS CLASS IS NOT SHOWING UP.
viewNew.addConstraints([
NSLayoutConstraint(item: titleLabel, attribute: .Width, relatedBy: .Equal, toItem: viewNew, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Left, relatedBy: .Equal, toItem: viewNew, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Top, relatedBy: .Equal, toItem: viewNew, attribute: .Top, multiplier: 1.0, constant: 0)
])
*/
viewNew.backgroundColor = UIColor.greenColor()
return viewNew
}
}
And this is my viewController class part where i try to instantiate the PostLineItem instances..
let guideView = UIView()
guideView.setTranslatesAutoresizingMaskIntoConstraints(false)
guideView.backgroundColor = UIColor.blackColor()
scrollView.addSubview(guideView)
scrollView.addConstraints([
NSLayoutConstraint(item: guideView, attribute: .Top, relatedBy: .Equal, toItem: scrollView, attribute: .Top, multiplier: 1.0, constant: 50),
NSLayoutConstraint(item: guideView, attribute: .Left, relatedBy: .Equal, toItem: scrollView, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: -30),
NSLayoutConstraint(item: guideView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:10)
])
guideView.backgroundColor = UIColor.blackColor()
var viewFromAbove = guideView
for post in 1...70 {
let v = PostLineItem(labelText: "Tst", labelHeader: "Tst2")
scrollView.addSubview(v)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: v, attribute: .Top, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Bottom, multiplier: 1.0, constant: 15),
NSLayoutConstraint(item: v, attribute: .Left, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Width, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 400)
])
viewFromAbove = v
}
scrollView.addConstraints([
NSLayoutConstraint(item: viewFromAbove, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: -10)
])
As you can see, first of all i create a guidview for the first PostLineItem and then adding the new instances and the constraints.. So..
If i do it this way the instances of the PostLineItem class will be at the same places and hides each others... I think, the NSLAyoutConstaint not effect.
But, as you can see at the commented part of the code, if i create a simple UILabel the constraints work fine, and all of the UILabel instances will be under each others..
UPDATE:
after i adding all of written in the answer it's look like this.. :(
That little red rect is my PostLineItem instance.. :(
UPDATED - all code.
I'm thinking you might be adding the constraints to the wrong views. For instance, the guideView height constraint should be added to the guideView, and not the scrollView. I would suggest instead you use the new way of activating constraints. Instead of adding them to the views, you just call the activateConstraints class method on NSLayoutConstraint:
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: guideView, attribute: .Top, relatedBy: .Equal, toItem: scrollView, attribute: .Top, multiplier: 1.0, constant: 24),
NSLayoutConstraint(item: guideView, attribute: .Left, relatedBy: .Equal, toItem: scrollView, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:4)
])
and
NSLayoutConstraints.activateConstraints([
NSLayoutConstraint(item: v, attribute: .Top, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Bottom, multiplier: 1.0, constant: 5),
NSLayoutConstraint(item: v, attribute: .Left, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Width, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Width, multiplier: 1.0, constant: 0),
])
Also, you are missing a constraint for the height of your PostLineItem, something like:
NSLayoutConstraint(item: v, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:10)
In your PostLineItem init, you need to add constraints for the timeLineBlock:
init(labelText: String , labelHeader: String) {
super.init(frame: CGRect.zeroRect)
self.labelText = labelText
self.labelHeader = labelHeader
let tlb = timeLineBlock()
self.addSubview(tlb)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: tlb, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Width, relatedBy: .Equal, toItem: self, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)
])
}
Here is my version. I'm getting much better results. Take a look... Note, I set up my scrollView entirely in Interface Builder and just added an outlet called scrollView that points to the contentView contained by my scrollView. That shouldn't matter. Everything else is as you implemented.
class PostLineItem: UIView {
var labelText : String!
var labelHeader : String!
init(labelText: String , labelHeader: String) {
super.init(frame: CGRect.zeroRect)
self.labelText = labelText
self.labelHeader = labelHeader
let tlb = timeLineBlock()
self.addSubview(tlb)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: tlb, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Width, relatedBy: .Equal, toItem: self, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)
])
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("required public")
}
private func timeLineBlock() -> UIView{
let viewNew = UIView()
viewNew.setTranslatesAutoresizingMaskIntoConstraints(false)
let titleLabel = UILabel()
titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
titleLabel.font = UIFont(name: "ArialMT", size: 20)
titleLabel.textColor = UIColor.blackColor()
titleLabel.text = labelHeader
titleLabel.numberOfLines = 0
viewNew.addSubview(titleLabel)
titleLabel.backgroundColor = UIColor.redColor()
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: titleLabel, attribute: .Width, relatedBy: .Equal, toItem: viewNew, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Left, relatedBy: .Equal, toItem: viewNew, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Top, relatedBy: .Equal, toItem: viewNew, attribute: .Top, multiplier: 1.0, constant: 0)
])
viewNew.backgroundColor = UIColor.greenColor()
return viewNew
}
}
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let guideView = UIView()
guideView.setTranslatesAutoresizingMaskIntoConstraints(false)
guideView.backgroundColor = UIColor.blackColor()
scrollView.addSubview(guideView)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: guideView, attribute: .Top, relatedBy: .Equal, toItem: scrollView, attribute: .Top, multiplier: 1.0, constant: 24),
NSLayoutConstraint(item: guideView, attribute: .Left, relatedBy: .Equal, toItem: scrollView, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:4)
])
guideView.backgroundColor = UIColor.blackColor()
var viewFromAbove = guideView
for post in 1...70 {
let v = PostLineItem(labelText: "Tst", labelHeader: "Tst2")
//let v = UILabel(frame: CGRectMake(0, 0, 10, 10))
//v.text = "Tst Now with this its working, and the constraint is fine."
v.setTranslatesAutoresizingMaskIntoConstraints(false)
scrollView.addSubview(v)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: v, attribute: .Top, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Bottom, multiplier: 1.0, constant: 5),
NSLayoutConstraint(item: v, attribute: .Left, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Width, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:30)
])
viewFromAbove = v
}
}
}
Related
I want to make editable-textview and imageview both scroll. (Like Vesper app!) I have to do this programmatically.
I followed this post uitextview-inside-uiscrollview-with-autolayout
And I made this in code, but it doesn't scroll!
noteTextView.isScrollEnabled = false
//Adding views
view.addSubview(bScrollView)
bScrollView.addSubview(nView)
nView.addSubview(photoImageView)
nView.addSubview(noteTextView)
//The scrollview constraint
let Sleft = NSLayoutConstraint(item: bScrollView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 0)
let Sright = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: bScrollView, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 0)
let Sbottom = NSLayoutConstraint(item: bottomLayoutGuide, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: bScrollView, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
let Stop = NSLayoutConstraint(item: bScrollView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 0)
//The view constraint
let Vleft = NSLayoutConstraint(item: nView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 0)
let Vright = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: nView, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 0)
let Vbottom = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: nView, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
let Vtop = NSLayoutConstraint(item: nView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 0)
let Vequal = NSLayoutConstraint(item: nView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.width, multiplier: 1, constant: 0)
//The textview constraint
let Nleft = NSLayoutConstraint(item: noteTextView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: nView, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 0)
let Nright = NSLayoutConstraint(item: nView, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: noteTextView, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 0)
let Nbottom = NSLayoutConstraint(item: nView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: noteTextView, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
let Ntop = NSLayoutConstraint(item: noteTextView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: photoImageView, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
let Nheight = NSLayoutConstraint(item: noteTextView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.greaterThanOrEqual, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 268)
//The imageview constraint
let Pleft = NSLayoutConstraint(item: photoImageView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: nView, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 0)
let Pright = NSLayoutConstraint(item: nView, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: photoImageView, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 0)
let Ptop = NSLayoutConstraint(item: photoImageView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: nView, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 0)
let Pheight = NSLayoutConstraint(item: photoImageView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 300)
NSLayoutConstraint.activate([
Sleft, Sright, Sbottom, Stop,
Vleft, Vright, Vbottom, Vtop, Vequal,
Nleft, Nright, Nbottom, Ntop, Nheight,
Pleft, Pright, Ptop, Pheight
])
How can I make textView and imageView like Vesper app? Is there are another way?
You're code has some issues, try this:
class ViewController: UIViewController {
var bScrollView:UIScrollView!
var nView:UIView!
var photoImageView:UIImageView!
var noteTextView:UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.translatesAutoresizingMaskIntoConstraints = false
bScrollView = UIScrollView.init(frame: CGRect.init(x: 0, y: 0, width: 50, height: 50))
bScrollView.backgroundColor = UIColor.black
nView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: 50, height: 50))
nView.backgroundColor = UIColor.blue
photoImageView = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: 50, height: 50))
photoImageView.backgroundColor = UIColor.red
noteTextView = UITextView.init(frame: CGRect.init(x: 0, y: 0, width: 50, height: 50))
noteTextView.backgroundColor = UIColor.yellow
noteTextView.clipsToBounds = true
bScrollView.translatesAutoresizingMaskIntoConstraints = false
nView.translatesAutoresizingMaskIntoConstraints = false
photoImageView.translatesAutoresizingMaskIntoConstraints = false
noteTextView.translatesAutoresizingMaskIntoConstraints = false
noteTextView.isScrollEnabled = false
//Adding views
view.addSubview(bScrollView)
bScrollView.addSubview(nView)
nView.addSubview(photoImageView)
nView.addSubview(noteTextView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//The scrollview constraint
let sLeading = NSLayoutConstraint(item: bScrollView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0)
let sTrailing = NSLayoutConstraint(item: bScrollView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
let sTop = NSLayoutConstraint(item: bScrollView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0)
let sBottom = NSLayoutConstraint(item: bScrollView, attribute: .bottom, relatedBy: .equal, toItem: bottomLayoutGuide, attribute: .bottom , multiplier: 1, constant: 0)
view.addConstraints([sLeading, sTrailing, sTop, sBottom])
//The view constraint
let vLeading = NSLayoutConstraint(item: nView, attribute: .leading, relatedBy: .equal, toItem: bScrollView, attribute: .leading, multiplier: 1, constant: 0)
let vTrailing = NSLayoutConstraint(item: nView, attribute: .trailing, relatedBy: .equal, toItem: bScrollView, attribute: .trailing, multiplier: 1, constant: 0)
let vTop = NSLayoutConstraint(item: nView, attribute: .top, relatedBy: .equal, toItem: bScrollView, attribute: .top, multiplier: 1, constant: 0)
let vBottom = NSLayoutConstraint(item: nView, attribute: .bottom, relatedBy: .equal, toItem: bScrollView, attribute: .bottom, multiplier: 1, constant: 0)
bScrollView.addConstraints([vLeading, vTrailing, vTop, vBottom])
let hEqual = NSLayoutConstraint(item: nView, attribute: .height, relatedBy: .equal, toItem: view, attribute: .height, multiplier: 1, constant: 0)
let wEqual = NSLayoutConstraint(item: nView, attribute: .width, relatedBy: .equal, toItem: view, attribute: .width, multiplier: 1, constant: 0)
view.addConstraints([hEqual, wEqual])
//The imageview constraint
let pLeading = NSLayoutConstraint(item: photoImageView, attribute: .leading, relatedBy: .equal, toItem: nView, attribute: .leading, multiplier: 1, constant: 0)
let pTrailing = NSLayoutConstraint(item: photoImageView, attribute: .trailing, relatedBy: .equal, toItem: nView, attribute: .trailing, multiplier: 1, constant: 0)
let pTop = NSLayoutConstraint(item: photoImageView, attribute: .top, relatedBy: .equal, toItem: nView, attribute: .top, multiplier: 1, constant: 0)
let pHeight = NSLayoutConstraint(item: photoImageView, attribute: .height, relatedBy: .equal, toItem: nView, attribute: .width, multiplier: 1.0, constant: 0)
nView.addConstraints([pLeading, pTrailing, pTop, pHeight])
//The textview constraint
let txtLeading = NSLayoutConstraint(item: noteTextView, attribute: .leading, relatedBy: .equal, toItem: nView, attribute: .leading, multiplier: 1, constant: 0)
let txtTrailing = NSLayoutConstraint(item: noteTextView, attribute: .trailing, relatedBy: .equal, toItem: nView, attribute: .trailing, multiplier: 1, constant: 0)
let txtTop = NSLayoutConstraint(item: noteTextView, attribute: .top, relatedBy: .equal, toItem: photoImageView, attribute: .bottom, multiplier: 1, constant: 0)
let txtBottom = NSLayoutConstraint(item: noteTextView, attribute: .bottom, relatedBy: .equal, toItem: nView, attribute: .bottom, multiplier: 1.0, constant: 0)
nView.addConstraints([txtTop, txtLeading, txtTrailing, txtBottom])
view.layoutIfNeeded()
}
}
I have a box that is initiated without a frame so it has 0 center and size.
let blackBox = UIView()
blackBox.backgroundColor = .blackColor()
blackBox.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(blackBox)
view.addConstraint(NSLayoutConstraint(item: blackBox, attribute: .Width, relatedBy: .Equal, toItem: view, attribute: .Width, multiplier: 0.1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: blackBox, attribute: .Height, relatedBy: .Equal, toItem: view, attribute: .Height, multiplier: 0.5, constant: 0))
view.addConstraint(NSLayoutConstraint(item: blackBox, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: blackBox, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0))
Is there anyway to insert a centered subview into the blackBox without using autolayout or is there a neater way I could/should use it. The only way I can see this happening is:
let blueBox = UIView()
blackBox.addSubview(blueBox)
blueBox.translatesAutoresizingMaskIntoConstraints = false
blueBox.backgroundColor = UIColor.blueColor()
view.addConstraint(NSLayoutConstraint(item: blueBox, attribute: .CenterX, relatedBy: .Equal, toItem: blackBox, attribute: .CenterX, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: blueBox, attribute: .CenterY, relatedBy: .Equal, toItem: blackBox, attribute: .CenterY, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: blueBox, attribute: .Width, relatedBy: .Equal, toItem: blackBox, attribute: .Width, multiplier: 0.4, constant: 0))
view.addConstraint(NSLayoutConstraint(item: blueBox, attribute: .Height, relatedBy: .Equal, toItem: blackBox, attribute: .Height, multiplier: 0.4, constant: 0))
I personally would use var bluebox = UIView(frame: CGRECT) and set the CGRect accordingly.
I am attempting to reproduce the constraints in this screenshot, which are applied to a static UITableViewCell:
Here is the code I'm using to try to do this:
#IBOutlet weak var cellTest: UITableViewCell!
override func viewDidLoad() {
super.viewDidLoad()
cellTest.backgroundColor = UIColor.yellowColor()
let vw = UIView()
vw.backgroundColor = UIColor.greenColor()
cellTest.contentView.addSubview(vw)
cellTest.contentView.translatesAutoresizingMaskIntoConstraints = false
vw.translatesAutoresizingMaskIntoConstraints = false
let constraintWidth = NSLayoutConstraint(item: vw, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 400)
let constraintHeight = NSLayoutConstraint(item: vw, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 150)
let constraintCentreX = NSLayoutConstraint(item: vw, attribute: .CenterX, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterX, multiplier: 1, constant: 0)
let constraintCentreY = NSLayoutConstraint(item: vw, attribute: .CenterY, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterY, multiplier: 1, constant: 0)
cellTest.contentView.addConstraints([constraintWidth, constraintHeight, constraintCentreX, constraintCentreY ])
}
However, below is the unexpected output, with the view in the top left instead of centred. Any help is much appreciated as I've spent quite some time trying to figure this out:
I needed to add constraints to the cell's contentView, as well. These are added to the cell itself.
Code and screenshot below.
#IBOutlet weak var cellTest: UITableViewCell!
override func viewDidLoad() {
super.viewDidLoad()
cellTest.backgroundColor = UIColor.yellowColor()
let vw = UIView()
vw.backgroundColor = UIColor.greenColor()
cellTest.contentView.addSubview(vw)
cellTest.contentView.translatesAutoresizingMaskIntoConstraints = false
vw.translatesAutoresizingMaskIntoConstraints = false
let bottomConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
cellTest.addConstraints([bottomConstraint, trailingConstraint, topConstraint, leadingConstraint])
let constraintWidth = NSLayoutConstraint(item: vw, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 200)
constraintWidth.priority = 1000
let constraintHeight = NSLayoutConstraint(item: vw, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 80)
constraintHeight.priority = 1000
let constraintCentreX = NSLayoutConstraint(item: vw, attribute: .CenterX, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterX, multiplier: 1, constant: 0)
constraintCentreX.priority = 1000
let constraintCentreY = NSLayoutConstraint(item: vw, attribute: .CenterY, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterY, multiplier: 1, constant: 0)
constraintCentreY.priority = 1000
cellTest.contentView.addConstraints([constraintWidth, constraintHeight, constraintCentreX, constraintCentreY ])
}
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.
Within UIView I have a method presentView():
public func presentView() {
UIApplication.sharedApplication().delegate?.window??.addSubview(self)
let blurEffect = UIBlurEffect(style: .Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.backgroundColor = UIColor.yellowColor()
addSubview(blurEffectView)
let topConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
self.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])
print("newframe: \(blurEffectView.frame)")
}
but sth is wrong because this is the output on console:
newframe: (0.0, 0.0, 0.0, 0.0)
and result is:
Remember about:
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
and then:
let topConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing, multiplier: 1, constant: 0)
addSubview(blurEffectView)
addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])
layoutIfNeeded()