Related
I am creating custom keyboard for ipad in which when I press my keyboard button and edit textfield textField(_:shouldChangeCharactersInRange:replacementString:) doesn't get called
import UIKit
class KeyBoardView: UIView{
enum KeyBoardType {
case AlphaNumeric
case Alpha
case Numeric
}
var textField: CustomKeyboardTextField!
var textInput: UITextInput?{
get{
return self.textField
}
}
var keyboardView: KeyBoardView!
let win: UIWindow = (((UIApplication.sharedApplication().delegate?.window)!)!)
let alphaKeyBoardView = KeyBoardAlphaView.instanceFromNib()
let numKeyBoardView = KeyBoardNumericView.instanceFromNib()
class func instanceFromNib() -> KeyBoardView{
let win: UIWindow = (((UIApplication.sharedApplication().delegate?.window)!)!)
let arrView = win.subviews
for view in arrView {
if view.isKindOfClass(KeyBoardView) {
view.removeFromSuperview()
break
}
}
return KeyBoardView(frame: CGRect(x: 0, y: win.bounds.size.height*0.6, width: win.bounds.size.width, height: win.bounds.size.height*0.4))
}
func keyboardTypeSet(notification: AnyObject) {
keyboardView = notification.object as! KeyBoardView
self.textField = keyboardView.textField
let arrView = win.subviews
var isPresentKView: Bool = false
for view in arrView {
if view.isKindOfClass(KeyBoardView) {
let arrSubView = view.subviews
for subView in arrSubView {
subView.removeFromSuperview()
}
isPresentKView = true
setkType(textField.kType)
break
}
}
if !isPresentKView {
setkType(textField.kType)
keyboardView.backgroundColor = UIColor.clearColor()
// setkType(textField.kType)
keyboardView.translatesAutoresizingMaskIntoConstraints = false
win.addSubview(keyboardView)
let leadingConstraint = NSLayoutConstraint(item: keyboardView, attribute: .Leading, relatedBy: .Equal, toItem: win, attribute: .Leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: keyboardView, attribute: .Trailing, relatedBy: .Equal, toItem: win, attribute: .Trailing, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: keyboardView, attribute: .Bottom, relatedBy: .Equal, toItem: win, attribute: .Bottom, multiplier: 1, constant: 0)
let heightConstraint = NSLayoutConstraint(item: keyboardView, attribute: .Height, relatedBy: .Equal, toItem: win, attribute: .Height, multiplier: 0.4, constant: 0)
win.addConstraints([leadingConstraint,trailingConstraint,bottomConstraint,heightConstraint])
keyboardView.layoutIfNeeded()
win.layoutIfNeeded()
}
}
func setkType(keyboardType: KeyBoardType) {
switch keyboardType {
case .AlphaNumeric:
alphaNumericKeyboard()
case .Alpha:
alphaKeyboard()
case .Numeric:
numericKeyboard()
}
}
func alphaNumericKeyboard() {
keyboardView.addSubview(alphaKeyBoardView)
keyboardView.addSubview(numKeyBoardView)
alphaKeyBoardView.translatesAutoresizingMaskIntoConstraints = false
numKeyBoardView.translatesAutoresizingMaskIntoConstraints = false
let alLeadingConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Leading, relatedBy: .Equal, toItem: keyboardView, attribute: .Leading, multiplier: 1, constant: 0)
let alBottomConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Bottom, relatedBy: .Equal, toItem: keyboardView, attribute: .Bottom, multiplier: 1, constant: 0)
let alTopConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Top, relatedBy: .Equal, toItem: keyboardView, attribute: .Top, multiplier: 1, constant: 0)
let alWidthConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Width, relatedBy: .Equal, toItem: keyboardView, attribute: .Width, multiplier: 0.7, constant: 0)
// let horizantalConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Right, relatedBy: .Equal, toItem: numKeyBoardView, attribute: .Left, multiplier: 1, constant: 0)
let numTrailingConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Trailing, relatedBy: .Equal, toItem: keyboardView, attribute: .Trailing, multiplier: 1, constant: 0)
let numBottomConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Bottom, relatedBy: .Equal, toItem: keyboardView, attribute: .Bottom, multiplier: 1, constant: 0)
let numLeadingConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Leading, relatedBy: .Equal, toItem: alphaKeyBoardView, attribute: .Trailing, multiplier: 1, constant: 0)
let numHeightConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Height, relatedBy: .Equal, toItem: keyboardView, attribute: .Height, multiplier: 1, constant: 0)
keyboardView.addConstraints([alLeadingConstraint,alBottomConstraint,alTopConstraint,alWidthConstraint,numBottomConstraint,numLeadingConstraint,numTrailingConstraint,numHeightConstraint])
}
func alphaKeyboard(){
alphaKeyBoardView.translatesAutoresizingMaskIntoConstraints = false
keyboardView.addSubview(alphaKeyBoardView)
let alLeadingConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Leading, relatedBy: .Equal, toItem: keyboardView, attribute: .Leading, multiplier: 1, constant: 0)
let alTrailingConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Trailing, relatedBy: .Equal, toItem: keyboardView, attribute: .Trailing, multiplier: 1, constant: 0)
let alTopConstriant = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Top, relatedBy: .Equal, toItem: keyboardView, attribute: .Top, multiplier: 1, constant: 0)
let alBottomConstraint = NSLayoutConstraint(item: alphaKeyBoardView, attribute: .Bottom, relatedBy: .Equal, toItem: keyboardView, attribute: .Bottom, multiplier: 1, constant: 0)
keyboardView.addConstraints([alLeadingConstraint,alTrailingConstraint,alTopConstriant,alBottomConstraint])
}
func numericKeyboard(){
numKeyBoardView.translatesAutoresizingMaskIntoConstraints = false
// keyboardView.frame = CGRect(x: 0, y: window!.bounds.size.height*0.6, width: window!.bounds.size.width*0.3, height: window!.bounds.height*0.4)
keyboardView.addSubview(numKeyBoardView)
let numLeadingConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Leading, relatedBy: .Equal, toItem: keyboardView, attribute: .Leading, multiplier: 1, constant: 0)
let numTopConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Top, relatedBy: .Equal, toItem: keyboardView, attribute: .Top, multiplier: 1, constant: 0)
let numWidthConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Width, relatedBy: .Equal, toItem: keyboardView, attribute: .Width, multiplier: 0.3, constant: 0)
let numBottomConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Bottom, relatedBy: .Equal, toItem: keyboardView, attribute: .Bottom, multiplier: 1, constant: 0)
// let numHeightConstraint = NSLayoutConstraint(item: numKeyBoardView, attribute: .Height, relatedBy: .Equal, toItem: keyboardView, attribute: .Height, multiplier: 1, constant: 0)
keyboardView.addConstraints([numLeadingConstraint,numTopConstraint,numBottomConstraint,numWidthConstraint])
}
}
Add
textField.delegate = self
Add UITextFieldDelegate to class
class KeyBoardView: UIView,UITextFieldDelegate {
how do i make two button "Like" and "Comment" with equal space on the left of "Like", equal space in the middle of "Like" and "Comment", and equal space on the right of "Comment" depending on the phone size
here is an image example:
Try the following code it is a bit different approach but hope it will work for you. It is better to set these constraints directly in Storyboard.
let deviceWidth = UIScreen.mainScreen().bounds.size.width
let buttonWidth = 75
let equalPadding = (deviceWidth - (2 * buttonWidth))/3
let centerXOfLikeButton = -(buttonWidth/2 + equalPadding/2)
let centerXOfCommentButton = (buttonWidth/2 + equalPadding/2)
// Like button constraints
let likeBtnTopConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Top, relatedBy: .Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 20)
let likeBtnWidthConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: buttonWidth)
let likeBtnHeightConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Height, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 40)
let likeBtnXConstraint = NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: centerXOfLikeButton)
self.view.addConstraint(likeBtnTopConstraint)
self.view.addConstraint(likeBtnWidthConstraint)
self.view.addConstraint(likeBtnHeightConstraint)
self.view.addConstraint(likeBtnXConstraint)
// Comment button constraints
let commentBtnTopConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Top, relatedBy: .Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 20)
let commentBtnWidthConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: buttonWidth)
let commentBtnHeightConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Height, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 40)
let commentBtnXConstraint = NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: centerXOfCommentButton)
self.view.addConstraint(commentBtnTopConstraint)
self.view.addConstraint(commentBtnWidthConstraint)
self.view.addConstraint(commentBtnHeightConstraint)
self.view.addConstraint(commentBtnXConstraint)
Using storyboard, please refer screenshots provided below
Crate Two button with equal width and equal height and give "titleEdgeInsets" on each button as bellow,
let insert = likeButton.frame.width / 4
commentButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: insert)
likeButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: insert, bottom: 0, right: 0)
When I add an NSLayoutConstraint to a view, it results in the view disappearing.
I am using the following code:
let test:UIView = UIView(frame: CGRectMake(0, 0, 100, 100))
test.backgroundColor = UIColor.blackColor()
self.view.addSubview(test)
test.translatesAutoresizingMaskIntoConstraints = false
let topCKCtr = NSLayoutConstraint(item: test, attribute: .CenterX, relatedBy: .Equal, toItem: test.superview, attribute: .CenterX, multiplier: 0.5, constant: 0)
topCKCtr.active = true
let topCKCtr1 = NSLayoutConstraint(item: test, attribute: .CenterY, relatedBy: .Equal, toItem: test.superview, attribute: .CenterY, multiplier: 0.5, constant: 0)
topCKCtr1.active = true
self.view.layoutIfNeeded()
self.view.setNeedsDisplay()
When I debug view hierarchy, i see that the view exists, even though it is not visible. See the below screenshot for details - only the constraint is visible, not the view:
There are so many things that needs to be discussed here.
When you use the following
test.translatesAutoresizingMaskIntoConstraints = false
Then it will totally rely on constraints to position and size a view.So you need to set height and width constraints of the view.
let topCKCtr2 = NSLayoutConstraint(item: test, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .Width, multiplier: 1.0, constant: 100)
let topCKCtr3 = NSLayoutConstraint(item: test, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1.0, constant: 100)
Finally This will be the code which you are looking for
let test:UIView = UIView(frame: CGRectMake(0, 0, 100, 100))
test.backgroundColor = UIColor.blackColor()
self.view.addSubview(test)
test.translatesAutoresizingMaskIntoConstraints = false
let topCKCtr = NSLayoutConstraint(item: test, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 0.5, constant: 0)
topCKCtr.active = true
let topCKCtr1 = NSLayoutConstraint(item: test, attribute: .CenterY, relatedBy: .Equal, toItem: self.view, attribute: .CenterY, multiplier: 0.5, constant: 0)
topCKCtr1.active = true
let topCKCtr2 = NSLayoutConstraint(item: test, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .Width, multiplier: 1.0, constant: 100)
topCKCtr2.active = true
let topCKCtr3 = NSLayoutConstraint(item: test, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1.0, constant: 100)
topCKCtr3.active = true
want to create UI such that constraint should be such that the space between the two button and the distance from the side edge should be same.
I am using the following code
func addConstraintsToBottomButtons()
{
let viewFrame = self.view.frame
let availableWidth:CGFloat = viewFrame.width - 60
let buttonDistance:CGFloat = availableWidth/3
let buttonWidth:CGFloat = 30.0
let buttonHeight:CGFloat = 30.0
var BtnOne = UIButton()
BtnOne.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(BtnOne)
BtnOne.backgroundColor = UIColor.redColor()
var btnTwo = UIButton()
btnTwo.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(btnTwo)
btnTwo.backgroundColor = UIColor.yellowColor()
//Views to add constraints to
//Metrics for Visual Format string
// Button One Constraint..
self.view .addConstraint(NSLayoutConstraint(item: BtnOne, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: bottonView, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: buttonDistance))
self.view .addConstraint(NSLayoutConstraint(item: BtnOne, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: bottonView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
self.view .addConstraint(NSLayoutConstraint(item: BtnOne, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0, constant: buttonWidth))
self.view .addConstraint(NSLayoutConstraint(item: BtnOne, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0, constant: buttonHeight))
// Button Two Constraint...
self.view .addConstraint(NSLayoutConstraint(item: btnTwo, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: bottonView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: -(buttonDistance)))
self.view .addConstraint(NSLayoutConstraint(item: btnTwo, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: bottonView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
self.view .addConstraint(NSLayoutConstraint(item: btnTwo, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0, constant: buttonWidth))
self.view .addConstraint(NSLayoutConstraint(item: btnTwo, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0, constant: buttonHeight))
}
let me suggest a workaround that will do just the thing you want:
Create three views in storyboard / pull them out of the same place where you get buttons - and use them as cushions between the edges of your screen and your buttons: anchor to edges, equal width, and lower horizontal compression than the actual buttons and it should behave as desired.
What is the best practice to resize superview with autolayout if we have inner NSView columns with dynamic heights?
For example. If we have two column layout, where left column height is bigger than right column, the superview height should be as right column height. Than, if we change right column height to be bigger than left column height, superview height should change to height of right column. How to accomplish this?
I made sample project to test this:
Initially we have layout with two columns, where .Bottom constraint of left NSView is attached to bottom of superview.
If we press Make Right Bigger button, I make height of right NSView bigger than left one.
So I want here superview to change height depending on bigger column (right column). Is there a good practice to do so?
Code:
import Cocoa
class ViewController: NSViewController {
let leftView = NSView()
let rightView = NSView()
let button = NSButton()
var rightViewHeightConstraint: NSLayoutConstraint?
override func loadView() {
self.view = TestView()
}
override func viewDidLoad() {
super.viewDidLoad()
leftView.backgroundColor = NSColor.redColor()
rightView.backgroundColor = NSColor.orangeColor()
layoutLeft(view, insertView: leftView)
layoutRight(view, insertView: rightView)
button.title = "Make Right Bigger"
button.target = self
button.action = "makeBigger:"
ViewControllerLayout.layoutBotton(view, insertView: button, bottom: -20)
}
func makeBigger(sender: AnyObject) {
rightViewHeightConstraint?.animator().constant = 150.0
}
func layoutLeft(containerView: NSView, insertView: NSView) {
insertView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(insertView)
let c1 = NSLayoutConstraint(item: insertView, attribute: .Left, relatedBy: .Equal, toItem: containerView, attribute: .Left, multiplier: 1.0, constant: 0.0)
let c2 = NSLayoutConstraint(item: insertView, attribute: .Width, relatedBy: .Equal, toItem: containerView, attribute: .Width, multiplier: 0.5, constant: 0.0)
let c3 = NSLayoutConstraint(item: insertView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100.0)
let c4 = NSLayoutConstraint(item: insertView, attribute: .Top, relatedBy: .Equal, toItem: containerView, attribute: .Top, multiplier: 1.0, constant: 0.0)
let c5 = NSLayoutConstraint(item: insertView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1.0, constant: -60.0)
containerView.addConstraint(c1)
containerView.addConstraint(c2)
containerView.addConstraint(c3)
containerView.addConstraint(c4)
containerView.addConstraint(c5)
}
func layoutRight(containerView: NSView, insertView: NSView) {
insertView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(insertView)
let c1 = NSLayoutConstraint(item: insertView, attribute: .Right, relatedBy: .Equal, toItem: containerView, attribute: .Right, multiplier: 1.0, constant: 0.0)
let c2 = NSLayoutConstraint(item: insertView, attribute: .Width, relatedBy: .Equal, toItem: containerView, attribute: .Width, multiplier: 0.5, constant: 0.0)
let c3 = NSLayoutConstraint(item: insertView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50.0)
let c4 = NSLayoutConstraint(item: insertView, attribute: .Top, relatedBy: .Equal, toItem: containerView, attribute: .Top, multiplier: 1.0, constant: 0.0)
let c5 = NSLayoutConstraint(item: insertView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1.0, constant: -60.0)
containerView.addConstraint(c1)
containerView.addConstraint(c2)
containerView.addConstraint(c3)
containerView.addConstraint(c4)
// containerView.addConstraint(c5) // Cant add .Bottom constraint here, because of different column sizes.
rightViewHeightConstraint = c3
}
}
struct ViewControllerLayout {
static func layoutBotton(containerView: NSView, insertView: NSView, bottom: Double) {
insertView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(insertView)
containerView.addConstraint(NSLayoutConstraint(item: insertView, attribute: .CenterX, relatedBy: .Equal, toItem: containerView, attribute: .CenterX, multiplier: 1.0, constant: 0.0))
containerView.addConstraint(NSLayoutConstraint(item: insertView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1.0, constant: CGFloat(bottom)))
}
}
Download test project: GitHub
Managed to accomplish this with constraints only. Just added the container view for columns and set its height as GreaterThanOrEqual to left column and right column.
view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Height, relatedBy: .GreaterThanOrEqual, toItem: leftView, attribute: .Height, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Height, relatedBy: .GreaterThanOrEqual, toItem: rightView, attribute: .Height, multiplier: 1, constant: 0))
First create a constraint on superview with height
let heightConstraint = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: greaterHeightAmongTwoColumns)
As discussed in the comment, you can post a notification and then let the super view know the updated frame. Super view would check if the updated height of any of the two columns is greater than its current height and update its heightConstraint declared above and then call
[self layoutIfNeeded]
on the superview's superview so that it is laid out with the new frame.