Let's assume that I have this UIView
:
with these relative constraints:
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *leftMarginConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topMarginConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *widthConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;
Okay now let's assume that when the user click on that UIButton
the button should move to the bottom-right corner of the view. We can easily use two constraints defining bottom space between the button and the bottom layout guide and right space (trailing space) from the button and the right edge of the view.
The problem it's that the UIButton
already had two constraints (left/top) AND two contraints defining its width and its height so we can't add two new constraints because they would conflict with the other ones.
Simple and common situation for an animation scenario, but it causing me some problems. Ideas?
EDIT
When the user taps on the UIButton
, I need that the button:
Am I seriously bound to use this messy code?
@implementation ViewController
{
NSLayoutConstraint *_topMarginConstraint;
NSLayoutConstraint *_leftMarginConstraint;
NSLayoutConstraint *_bottomMarginConstraint;
NSLayoutConstraint *_rightMarginConstraint;
}
- (IBAction)buttonPressed:(id)sender
{
UIButton *button = sender;
// 1.
[sender setTitle:@"Second" forState:UIControlStateNormal];
// 2.
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[button removeConstraints:@[self.leftMarginConstraint, self.topMarginConstraint]];
_bottomMarginConstraint = [NSLayoutConstraint constraintWithItem:self.view
attribute:NSLayoutAttributeBottom
relatedBy:0 toItem:button
attribute:NSLayoutAttributeBottom
multiplier:1
constant:20];
[self.view addConstraint:_bottomMarginConstraint];
_rightMarginConstraint = [NSLayoutConstraint constraintWithItem:self.view
attribute:NSLayoutAttributeRight
relatedBy:0 toItem:button
attribute:NSLayoutAttributeRight
multiplier:1
constant:20];
[self.view addConstraint:_rightMarginConstraint];
[UIView animateWithDuration:1 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
// 3.
[sender setTitle:@"Third" forState:UIControlStateNormal];
// 4.
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[button removeConstraint:_bottomMarginConstraint];
_topMarginConstraint = [NSLayoutConstraint constraintWithItem:self.view
attribute:NSLayoutAttributeTop
relatedBy:0 toItem:button
attribute:NSLayoutAttributeTop
multiplier:1
constant:20];
[UIView animateWithDuration:1 animations:^{
[self.view layoutIfNeeded];
}];
});
}];
});
}
Serious? :D
Delete the left and top constraints, add the bottom and right constraints, then call layoutIfNeeded in an animation block to animate to the new position. The code in the second method, move2 could be embedded in the completion block of move1, but I find it easier to read if you keep the two moves in separate methods (it does necessitate the addition of another property, bottomCon):
- (IBAction)move1:(UIButton *)sender {
[sender setTitle:@"Second" forState:UIControlStateNormal];
[sender layoutIfNeeded];
[self.view removeConstraints:@[self.leftCon,self.topCon]];
self.bottomCon = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:0 toItem:self.button attribute:NSLayoutAttributeBottom multiplier:1 constant:20];
[self.view addConstraint:self.bottomCon];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeRight relatedBy:0 toItem:self.button attribute:NSLayoutAttributeRight multiplier:1 constant:20]];
[UIView animateWithDuration:1 delay:1.0 options:0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
[sender setTitle:@"Third" forState:UIControlStateNormal];
[self move2];
}];
}
-(void)move2 {
[self.view removeConstraint:self.bottomCon];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.button attribute:NSLayoutAttributeTop multiplier:1 constant:-20]];
[UIView animateWithDuration:1 delay:1.0 options:0 animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
For animation you need to change constant of the left and top constraint instead of adding new constraint. As follows:
self.mBtnTopConstraint.constant = yourval1;
self.mBtmLeftConstraint.constant = yourval2;
[yourbtn setNeedsUpdateConstraints];
[UIView animateWithDuration:0.5 animations:^{
[yourbtn layoutIfNeeded];
} completion:^(BOOL isFinished){
}];
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With