In my app, I have the following setup:
TextView (self.textView)
Toolbar
When the keyboard become visible, I add a constraint that pushes the bottom of the text view up with the required number of pixels.
spacer =[NSLayoutConstraint
constraintWithItem:self.textView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-height];
[self.view addConstraint:spacer];
When the keyboard disappears, I remove the constraint.
THIS WORKS FINE. However...
I want to add an imageview that lies on top of the text view. This seems straightforward. But now the "dismiss keyboard" resize is broken.
Here's the code I use to create the imageview, and pin it to the textview bounds.
self.overlay = [[UIImageView alloc] init];
[self.overlay setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:self.overlay];
[self.view addConstraint: [NSLayoutConstraint
constraintWithItem:self.overlay
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.textView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]];
[self.view addConstraint: [NSLayoutConstraint
constraintWithItem:self.overlay
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.textView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0]];
[self.view addConstraint: [NSLayoutConstraint
constraintWithItem:self.overlay
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.textView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0]];
[self.view addConstraint: [NSLayoutConstraint
constraintWithItem:self.overlay
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.textView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0]];
[self.view layoutIfNeeded];
Here's how it should look:
Initial before keyboard showing
Keyboard showing
Keyboard removed. Layout should be back to initial state, but instead I get this
Solution: Set the content hugging priority for the tool bar to 1.000 to avoid that it gets all stretched out.
Related
In my application I have inserted UIViews on view controller. My main requirement is that I want to set equal widths for both UIViews using auto-layouts "Constraint with item format".
For this I have written some code but I did not get equal widths. What did I do here wrong?
I want get result like below image (i.e need to set equal widths for both UIViews).
My code:
#import "ViewController8.h"
#interface ViewController8 ()
{
UIView * myView1;
UIView * myView2;
}
#end
#implementation ViewController8
- (void)viewDidLoad {
[super viewDidLoad];
myView1 = [[UIView alloc] init];
myView1.backgroundColor = [UIColor lightGrayColor];
myView1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:myView1];
myView2 = [[UIView alloc] init];
myView2.backgroundColor = [UIColor redColor];
myView2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:myView2];
[self operation2];
}
-(void)operation2
{
//Applying autolayouts for myview2
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-30]];
//Applying autolayouts for myview1
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:myView2
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:-30]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-30]];
}
Equal width constraint is not there in your posted code. Try adding this
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:myView1
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
It's enough to add the equal-width constraint
[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:myView2
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
You must not define the width of the two views explicitly using constraints because view1 is pinned to the leading edge of the superview, view2 is pinned to the trailing edge of the superview and the trailing edge of view1 is pinned to the leading edge of view2. Hence, the constraint system is fully determined after adding the above equal-width constraint.
This is what adding the constraint will lead to:
Contemporary solution is using NSLayoutAnchor
myView1.widthAnchor.constraint(equalTo: myView2.widthAnchor)
don't forget to activate this using isActive = true, or via NSLayoutConstraint.activate().
How to add constraint for subview of view controller
explain briefly
// create a new view
self.containerView = [UIView new];
// before adding constraints always add respective view to superview
[self.view addSubview:self.containerView];
[self.containerView setTranslatesAutoresizingMaskIntoConstraints:false];
// add container on newly added view
NSLayoutConstraint *topConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
NSLayoutConstraint *leadingConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.containerView.superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
NSLayoutConstraint *trailingConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.containerView.superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
NSLayoutConstraint *bottomConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.bottomLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
// add constraint to superview of respective view
[self.view addConstraints:#[topConstraintContainer,leadingConstraintContainer,trailingConstraintContainer,bottomConstraintContainer]];
There are alot of possibilities, but this is the main flow
Also there are third party libraries available which makes adding constraints easier, like
PureLayout
I added a FBAdView to a UIView in the view controller.
(I set the view background to red)
the FBAdView was created with adSize of kFBAdSizeHeight50Banner.
The problem is that the FBAdView calculates its width when it is being added, but after rotating the device it doesn't calculate its width again
I tried using autolayout but it didn't work
code for adding the FBAdview (Adding to UILabel with red backgroud)
FBAdView *fbAdView = [[FBAdView alloc] initWithPlacementID:#"***************_***************"
adSize:kFBAdSizeHeight50Banner
rootViewController:self];
fbAdView.delegate = self;
[fbAdView loadAd];
[self.banner addSubview:fbAdView];
code for autolayout - doesn't work
// Width constraint, parent view width
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.banner
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
// Height constraint, parent view height
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.banner
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0]];
// Center horizontally
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.banner
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
// Center vertically
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.banner
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
print screen
when the banner is added it fit the screen width
after rotating it doesn't change its width (like its parent red view)
I think you're missing some constraints.
Adding these lines (might need some minor changes) makes your code work:
self.banner.translatesAutoresizingMaskIntoConstraints = NO;
fbAdView.translatesAutoresizingMaskIntoConstraints = NO;
// Width constraint
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.banner
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
// Height constraint
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[banner(==50)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(banner)]];
I've posted a sample project at https://github.com/overlordnyaldee/BannerAutoLayout
I have programatically set an image to a UIViewController background. How can i add autolayout programatically so it gets displayed both in iPad and iPhone?
The code is below:
UIImageView *bkImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"bkImage.png"]];
[self.view addSubview:bkImage];
1) Create the necessary constraint using one of the NSLayoutConstraint class methods that give you a constraint.
2) Add it to the view using the UIview's methods for adding a constraint.
This adds constraints of 0 leading, 0 trailing, 0 top and 0 bottom. You can modify them as per your needs.
[bkImage setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:bkImage
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:bkImage
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:bkImage
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:bkImage
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f]];
I am using this spinner in a project: https://github.com/misterwell/MMMaterialDesignSpinner
How would I add it to the center of the screen with autolayouts so that when the device rotates, it still stays in the center of the screen?
You can add autolayout constraints programmatically. You can use 4 constraints - center x, center y, width and height:
[self.spinner setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self.spinner attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f];
NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:self.spinner attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.spinner attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:kSpinnerWidth];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.spinner attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:kSpinnerHeight];
[self.view addConstraints:#[ centerXConstraint, centerYConstraint, widthConstraint, heightConstraint]];
If you're using storyboards you could add the Horizontal Centre in Container and Vertical Centre in Container. To do this, click on the view in interface builder and look at the bottom right of the IB screen. Click on the first of 4 buttons and check the appropriate boxes.
If you're using code you could write spinner.center = self.view.center in viewDidLayoutSubviews().