Slide In A UIView by updating constraints - ios

I am trying to animate a UIView by updating its constraints. I want to initially place the view at the bottom of the screen (off screen) and then set the top constraint to 0 so that the animation shows the view moving upwards.
I have tried the following with no luck at all, the animation is incorrect.
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
//CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
self.viewSearchWrapper.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.viewSearchWrapper];
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:self.viewSearchWrapper
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.f];
// Leading
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:self.viewSearchWrapper
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.f];
// Bottom
NSLayoutConstraint *bottom = [NSLayoutConstraint
constraintWithItem:self.viewSearchWrapper
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.f];
// Bottom
NSLayoutConstraint *top = [NSLayoutConstraint
constraintWithItem:self.viewSearchWrapper
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:screenHeight];
[self.view addConstraint:trailing];
[self.view addConstraint:bottom];
[self.view addConstraint:leading];
[self.view addConstraint:top];
[self.viewSearchWrapper setNeedsUpdateConstraints];
[top setConstant:0.f];
[UIView animateWithDuration:1 animations:^{
[self.view layoutIfNeeded];
}];

Add layoutIfNeeded to first set the initial constraint to viewSearchWrapper.
// .... keep the code assigning the constraints as it is.
[self.view layoutIfNeeded]; // This will set the initial frame of viewSearchWrapper
[self.viewSearchWrapper setNeedsUpdateConstraints];
[top setConstant:0.f];
[UIView animateWithDuration:1 animations:^{
[self.view layoutIfNeeded];
}];

Add [top setConstant:0.f] inside animateWithDuration as shown below:
[UIView animateWithDuration:1 animations:^{
[top setConstant:0.f];
[self.view layoutIfNeeded];
}];

Related

changes subView frame when rotate

i add subView(backgroundView) in uiview in my base view controller its working well in potratate but when i change orientation from potraite to landscape its frame size is same as potrait i want to change size of subview when rotate.
UIView *activityView = [[UIView alloc] initWithFrame:self.view.bounds];
CGRect frame = activityView.frame;
activityView.frame = frame;
activityView.backgroundColor = [UIColor clearColor];
activityView.alpha = 0.0f;
[self.view addSubview:activityView];
self.activityView = activityView;
UIView *backgroundView = [[UIView alloc]initWithFrame:activityView.bounds];
backgroundView.alpha = 0.0f;
[backgroundView setBackgroundColor:[UIColor lightGrayColor]];
[self.activityView backgroundView];
UIActivityIndicatorView *spinning = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.activityView spinning];
spinning.center = activityView.center;
self.activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[spinning setColor:[UIColor lightGrayColor]];
[spinning startAnimating];
To do this you must add constraints to your view (AutoLayout).
For example :
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0]];
Edit :
Don't forget to set translatesAutoresizingMaskIntoConstraints property to NO on views.
(Replace self.view and containerView with your views).

How to change or update NSLayoutConstraint programmatically

I have implemented AutoLayout programmatically using the Code :
- (void)addConstraintWithListNavigationViewController:(UIView *)listViewNavigation y:(CGFloat)y height:(CGFloat)height
{
//WIDTH_ListTableView = 0.4
//set x = 0;
NSLayoutConstraint *constraintToAnimate1 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:0.00
constant:0];
[self.view addConstraint:constraintToAnimate1];
//set y = y;
NSLayoutConstraint *constraintToAnimate2 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:0.00
constant:y];
[self.view addConstraint:constraintToAnimate2];
//set Width = self.view.frame.size.width*0.4
NSLayoutConstraint *constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1-WIDTH_ListTableView
constant:0.0];
[self.view addConstraint:constraintToAnimate3];
//Set height = height
NSLayoutConstraint *constraintToAnimate4 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.00
constant:height];
[self.view addConstraint:constraintToAnimate4];
}
And this works perfect, but every-time this ViewController receives a Notification, it will run:
[self.view layoutIfNeeded];
But I want to set the width of listViewNavigation according a boolean variable connected.
if(connected){
listViewNavigation.view.frame.size.width = 0.4 * self.view.frame.size.width;
}
else{
listViewNavigation.view.frame.size.width = 0.6 * self.view.frame.size.width;
}
But i do not know how can I update the NSLayoutConstraint :
NSLayoutConstraint *constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:PreView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1 - WIDTH_ListTableView
constant:0.0];
[self.view addConstraint:constraintToAnimate3];
when this ViewController receive the notification.
I think you have 2 options.
Option 1
Keep a property
#property (strong,nonatomic)NSLayoutConstraint *constraintToAnimate3;
Then use this property to
self.constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:PreView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1
constant:-1 * 0.4 * self.view.frame.size.width];
[self.view addConstraint:self.constraintToAnimate3];
When you want to change
if(connected){
self.constraintToAnimate3.constant = -1 *0.6 * self.view.frame.size.width;
}
else{
self.constraintToAnimate3.constant = -1 *0.4 * self.view.frame.size.width;
}
[UIView animateWithDuration:yourduration animations:^{
[self.view layoutIfNeeded];
}];
Option 2
Set an identifier of constraintToAnimate3
constraintToAnimate3.identifier = #"1234"
Then search to get the constraint
NSLayoutConstraint * constraint3 = nil;
NSArray * constraints = self.view.constraints;
for (NSLayoutConstraint * constraint in constraints) {
if ([constraint.identifier isEqualToString:#"1234"]) {
constraint3 = constraint;
break;
}
}
Then change the constant as shown in Option1
Update:
If use constant in the code I post
PreView.frame.size.with = self.view.size.width * multiplier + constant
OK, I figure out.
[self.view removeConstraint:self.constraintOld];
[self.view addConstraint:self.constraintNew];
[UIView animateWithDuration:time animations:^{
[self.view layoutIfNeeded];
}];
It's essential that you don't just add the constraints to your view, but that you also remember them.
It's easiest to change a constraint if you only need to change its constant - the constant is the only part of a constraint that can be changed later repeatedly. To do that, you need to store the constraint on its own.
Otherwise you need to remove old constraints and add new ones. Since you usually have more than one constraint, store arrays with sets of constraints that may need to be replaced, then update the whole array. You can also use the activateConstraints and deactivateConstraints methods.

How to animate NSLayoutConstraint without IBOutlet

I have a View Controller containing a view (of another controller) and a tab bar at the bottom. I want to add an iAD banner such that when an ad is loaded and unloaded, the contained view is resized accordingly.
/* AutoLayout */
/* pin Left of child to left of parent */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:child.view
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0]];
/* pin Right of child to right of parent */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:child.view
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0]];
/* pin top of child to bottom of nav bar(or status bar if no nav bar) */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:child.view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]];
/* pin Top of tab bar to bottom of child view */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:child.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]];
/*
* adConstraint is an instance variable to hold the constraint I want to animate
* Note that it is not an IBOutlet
*/
adConstraint = [NSLayoutConstraint constraintWithItem:child.view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0];
[self.view addConstraint:adConstraint];
In my delegate methods i have the following
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
UIView animateWithDuration:1 animations:^{
adConstraint.constant = -banner.frame.size.height;
[self.view layoutIfNeeded];
}];
}
and
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
UIView animateWithDuration:1 animations:^{
adConstraint.constant = 0;
[self.view layoutIfNeeded];
}];
}
I seriously need help with this! Is it even possible to achieve this without Storyboard and the IBOutlet or am I doing something (terribly) wrong?
Please Help?!
*********************** EDIT: ************************
I've noticed a problem; The ad shows up but bannerDidLoadAd is not called. I know this because I added log statements in it. Does anyone know why this might be happening????
Try calling
[self.view setNeedsUpdateConstraints];
before
[self.view layoutIfNeeded];
It should work!
[UIView animateWithDuration:1 animations:^{
adConstraint.constant = 0;
[self.view setNeedsUpdateConstraints];
[self.view layoutIfNeeded];
}];

iOS Autolayout Constraints animation breaks inner view position

I am using Autolayout and contraints, I need to animate a view as if it came from a thumbnail to fullscreen. The view has one child, a webview which is attached to its four sides with constraints.
This is what I do:
- (void)animate {
trailingConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual toItem:self.superview.superview attribute:NSLayoutAttributeTrailing multiplier:1
constant:_trailing];
leadingConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual toItem:self.superview.superview attribute:NSLayoutAttributeLeading multiplier:1
constant:_leading];
bottomConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual toItem:self.superview.superview attribute:NSLayoutAttributeBottom multiplier:1
constant:_bottom];
topConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual toItem:self.superview.superview attribute:NSLayoutAttributeTop multiplier:1
constant:_top];
[self.superview.superview addConstraint:trailingConstraint];
[self.superview.superview addConstraint:leadingConstraint];
[self.superview.superview addConstraint:topConstraint];
[self.superview.superview addConstraint:bottomConstraint];
[self.superview.superview layoutIfNeeded];
self.alpha = 0;
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.closeButton.hidden = NO;
self.alpha = 1.0f;
trailingConstraint.constant = 0;
leadingConstraint.constant = 0;
bottomConstraint.constant = 0;
topConstraint.constant = 0;
[self.superview.superview layoutIfNeeded];
} completion:nil];
}
I call that method after adding the view to the superview, and I call the opposite when I close the view
It works fine. But the inner view, a UIWebview does not resize together with the animation, it takes the final size before the animation starts, it flickers and becomes big (or small when closing) and then the animation starts on self and is self resizes correctly.
What could be wrong?
The webview does not have size constraints, it has position constraints, the same as self basically -> 0 for four sides to self and these constraints are not changed.

UITableView viewForHeaderInSection UIView animation issue

I have a custom UIView that has two labels, one of which is animated (it blinks like a cursor and looks quite fly). This view works fine EXCEPT when I try to use it for a tableView's header; the animation doesn't repeat even though I specify UIViewAnimationOptionRepeat.
My class:
#implementation HXTEST {
UILabel *cursorLabel;
}
#pragma mark - inits
- (id) initForLabel:(UILabel *)forLabel {
self = [super init];
if (self) {
self.translatesAutoresizingMaskIntoConstraints = NO;
CGRect abba = [forLabel.text boundingRectWithSize:forLabel.frame.size
options:NSStringDrawingUsesFontLeading
attributes:#{ NSFontAttributeName : forLabel.font}
context:[NSStringDrawingContext new]];
float width = CGRectGetWidth(abba) * 1.005f;
self->cursorLabel = [UILabel new];
self->cursorLabel.textColor = forLabel.textColor;
self->cursorLabel.font = forLabel.font;
self->cursorLabel.text = #"▏";
self->cursorLabel.adjustsFontSizeToFitWidth = forLabel.adjustsFontSizeToFitWidth;
self->cursorLabel.minimumScaleFactor = forLabel.minimumScaleFactor;
self->cursorLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:forLabel];
[self addSubview:self->cursorLabel];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f
constant:width]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:forLabel
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.f
constant:forLabel.font.pointSize]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.f
constant:0.f]];
}
[UIView animateWithDuration:1.f
delay:0.f
options:UIViewAnimationOptionRepeat
animations:^{
self->cursorLabel.alpha = 1.f;
self->cursorLabel.alpha = 0.f;
}
completion:nil];
return self;
}
#end
Is there something about tableView headers and their presentation? Is there some other combination of UIViewAnimationOptions I should consider? Instead of automatically starting the animation block should I trigger it off some event like the headerView's appearance or some such?
Aha! Although [UIView areAnimationsEnabled] defaults to TRUE, it was for some reason FALSE. I forced it with
[UIView setAnimationsEnabled:YES];
before the animation block and all works now! I don't know why it was off...
Try like this using UIViewAnimationOptionAutoreverse option as well:
void (^animationLabel) (void) = ^{
blinkLabel.alpha = 0;
};
void (^completionLabel) (BOOL) = ^(BOOL f) {
blinkLabel.alpha = 1;
};
NSUInteger opts = UIViewAnimationOptionAutoreverse |
UIViewAnimationOptionRepeat;
[UIView animateWithDuration:1.f delay:0 options:opts
animations:animationLabel completion:completionLabel];
Hope it helps!

Resources