iOS Minimize view and all subviews to top left - ios

I have a UIView with a few subviews (and a few subviews in those). I am trying to minimize this entire view into the top left of the screen until it reaches a certain size (20 x 20) but am having trouble doing just that.
I first tried [UIView beginAnimations:nil context:nil]; but this didn't resize the subviews. Also, due to the padding and amount of other subviews, it would be very hard to set each subview frame to some new size and make it all work well.
I then tried this code:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.myCardsCarousel.layer setAnchorPoint:CGPointMake(0.0f, 0.0f)];
[self.myCardsCarousel setTransform:CGAffineTransformMakeScale(0.0f, 0.0f)];
CGRect addCardsButtonFrame = self.addCardsButton.frame;
addCardsButtonFrame.size.height = 0.0f;
[self.addCardsButton setFrame:addCardsButtonFrame];
[UIView commitAnimations];
But this doesn't minimize to the top left of the screen. Instead, it minimizes to the dead center of the screen.
How can I anchor this to the top left of the screen? Also, how can I stop a CGAffineTransformMakeScale() when the view reaches a certain size?

One possible solution is to create a snapshot of the view, and animate the snapshot into the corner (assuming that it's ok for the minimized view to be static). The general sequence of events is
create a snapshot of the parent view into a memory bitmap
create a UIImageView from the snapshot
position the UIImageView in front of the parent view
hide the parent view using its hidden property
animate the UIImageView into the corner
To restore the view
animate the UIImageView back to its original location
unhide the parent view
remove the UIImageView and discard it
To start, you need a property for the UIImageView
#property (strong, nonatomic) UIImageView *snapshotView;
Here's the code to minimize the view
// create a snapshot image of the parent view
UIGraphicsBeginImageContextWithOptions( self.parentView.bounds.size, YES, 0 );
CGContextRef context = UIGraphicsGetCurrentContext();
[self.parentView.layer renderInContext:context];
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// create a UIImageView from the snapshot
self.snapshotView = [[UIImageView alloc] initWithFrame:self.parentView.frame];
self.snapshotView.image = snapshot;
[self.view addSubview:self.snapshotView];
// hide the parent view in place, while animating the snapshot view into the corner
self.parentView.hidden = YES;
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^
{
self.snapshotView.frame = CGRectMake( 0, 0, 20, 20 );
}
completion:nil];
Here's the code to restore the view
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^
{
// animate the snapshot view back to original size
self.snapshotView.frame = self.parentView.frame;
}
completion:^(BOOL finished)
{
// reveal the parent view and discard the snapshot view
self.parentView.hidden = NO;
[self.snapshotView removeFromSuperview];
self.snapshotView = nil;
}];

Related

How to load a UIView from a certain frame

I want to load a view from a certain place within my current view. Currently, my view consists of a calendar with day buttons, each representing a day within the month. One of the buttons is highlighted to represent the "today" button. I want to load my view from that position and grow that view from that small frame.
More specifically, I want to load yearCalendarView from the frame of a button inside curMonthView. Here is what I have currently:
// animate in year calendar
_yearCalendarView.hidden = NO;
self.curMonthView.monthLabel.hidden = YES;
CalendarMonthView *monthView = [CalendarMonthView new];
monthView.delegate = self;
CGRect buttonFrame = _currentDayButtonFrame;
_yearCalendarView.frame = buttonFrame;
_yearCalendarView.center = buttonFrame.origin;
_yearCalendarView.alpha = 0.0;
[UIView beginAnimations:#"animateYearCalendarIn" context:nil];
[UIView setAnimationDuration:0.5]; // kAnimation_AnimateInDuration];
[UIView setAnimationCurve:UIViewAnimationOptionCurveLinear];
_yearCalendarView.alpha = 1.0;
_yearCalendarView.frame = CGRectMake(_monthSwiperScrollView.frame.origin.x, _monthBarImageView.frame.size.height + 20, _monthSwiperScrollView.frame.size.width + 2, _yearFlyoutHeight);
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector (yearCalendarAnimationDidStop:finished:context:)];
[_yearCalendarView setFrameHeight:_yearFlyoutHeight];
[UIView commitAnimations]; // start animation
_monthBarImageView.highlighted = YES;
[self _refreshMonthButton:NO];
I have the frame of the today button, but when I do this animation, it does not grow from that frame rather it just comes in from the bottom left corner of the new view _yearCalendarView.
How do I achieve this effect?
TLDR: Load a view from a known frame and then grow that frame to fit the screen.

Move a UIView with start point

I have this code below who move my UIView to left:
- (void)viewDidLoad {
[super viewDidLoad];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:4];
int xOriginal = 91;
CGRect rect = imagem.frame;
int x = rect.origin.x;
int y = rect.origin.y;
int w = rect.size.width;
int h = rect.size.height;
if(x == xOriginal){
imagem.frame = CGRectMake(x+100, y, w, h);
}else{
imagem.frame = CGRectMake(x-100, y, w, h);
}
[UIView commitAnimations];
}
My coordinate of my view is x = 91 (Center of the superView), When I start my app my UIView start left and go to center, instead of center and go to right, Why this is happening?
How to make my UIView start in center (x=91) and go to right (91+100), instead of left to center?
[UIImageView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
imagem.frame=CGRectMake(imagem.frame.origin.x+100, imagem.frame.origin.y, imagem.frame.size.width, imagem.frame.size.height);
} completion:^(BOOL finished) {
//code for completion
NSLog(#"Animation complete");
}];
Autolayout and frame animations are not good friends. Try to animate constraints instead of directly the frame.
You can create outlets of your constraints, and set the constant property of the constraint in your code to move your views.
You also call -[view layoutIfNeeded] to refresh your constraints while in an animation block.
Else you can remove all of your view constraints and animate its frame fearlessly.
Initially image.frame = CGRectMake(91,100,20,20);
So imageview starting point is 0
[UIView animateWithDuration:5.0
animations:^{
//Animation code goes here
image.frame = CGRectMake(191,100,20,20); //Now imageview moves from 0 to 100
} completion:^(BOOL finished) {
//Code to run once the animation is completed goes here
}];
As the other poster says, you can't animate a view's frame in XIBs/storyboards that use AutoLayout.
Instead you have to animate a constraint that's attached to the view.
What you do is to create a constraint (or multiple constraints) and connect it to an IBOutlet. Then, in your animation code, you calculate the changes to the constraint(s) and change the constant for the appropriate constraints.
For example, if you wanted to shift the vertical position of a view, set up a constraint that sets the vertical position of your view, and link it to an IBOutlet called viewConstraint. Then you'd use code like this:
[myView animateWithDuration: .25
animations: ^
{
viewConstraint.constant -= shiftAmount;
[self.view layoutIfNeeded];
}
];

Calling [table reloadData] removes table's position change from [uiview animatewithduration]

There is a button that horizontally shifts my table.
- (void)togglePreferencePageVisibility:(id)sender {
int translation = [self preferencesVisible] ? -PREFERENCE_TRANSLATION_HEIGHT : PREFERENCE_TRANSLATION_HEIGHT;
//animate tableview down
[UIView animateWithDuration:0.3
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
_table.center = CGPointMake(_table.center.x, _table.center.y+translation);
}
completion:^(BOOL finished){
}];
}
When I call [_table reloadData], the table reverts to its original position. I tried manually readjusting the table position, like so
NSLog(#"before %#", NSStringFromCGRect(_table.frame));
[_table reloadData];
_table.frame = CGRectMake(initialTablePosition.x, initialTablePosition.y+PREFERENCE_TRANSLATION_HEIGHT, _table.frame.size.width, _table.frame.size.height);
NSLog(#"after %#", NSStringFromCGRect(_table.frame));
but no luck. Also the frame's have the same y position before and after.
You need to also adjust the auto layout constraints using the NSLayoutConstraint class. You can add, remove or change the values of NSLayoutConstraints. This is a VERY common question on stack overflow right now, due to the change from iOS 7 to iOS 8.
If you do not adjust the layout constraints then the view will be repositioned back to its original location. reloadData redraws the UITableView which causes the view hierarchy to reexamine its positions e.t.c.
As an example of making a view with a width constraint narrower:
CGRect frame = myView.frame;
frame.size.width -= 100;
//Next line now needed in iOS 8
myWidthConstraint.constant -= 100;
[UIView animateWithDuration:0.5 animations:^{
[myView setFrame:frame];
}];
EDIT: moving back example:
CGRect frame = myView.frame;
frame.size.width += 100;
//Next line now needed in iOS 8
myWidthConstraint.constant += 100;
[UIView animateWithDuration:0.5 animations:^{
[myView setFrame:frame];
}];
When using auto layout, you should not set any frames. If you do, when the view needs to redraw itself, the frame will be reset to the frame defined by its constraints. You should add an IBOutlet to a constraint between your table view and the top (or bottom what ever works for your use) of its superview (I'll call it topCon in the example below).
- (void)togglePreferencePageVisibility:(id)sender {
int translation = [self preferencesVisible] ? -PREFERENCE_TRANSLATION_HEIGHT : PREFERENCE_TRANSLATION_HEIGHT;
//animate tableview down
self.topCon.constant += translation; // this might need to be "-=" depending on whether your constraint is to the top or bottom
[UIView animateWithDuration:0.3
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
[self.view layoutIfNeeded];
}
completion:^(BOOL finished){
}];
}

Animate size of View keeping its bottom left point fixed

I have a UIView at the bottom left of its superview, i.e.its frame is like
[myView setFrame:CGRectMake(0,superView.bounds.size.height-myViewHeight,myViewWidth,myViewHeight)];
I want to animate its size such that its bottom left point remains fixed at its position. I am not sure how to play with anchor point property of layers.
Currently I am increasing its size using the following lines of code.
[UIView animateWithDuration:0.2 animations:^{
[bottomLbl setFrame:CGRectMake(0, bottomView.bounds.size.height-250, 300, 250)];
This works fine but when I try to bring back to its original size, its bottom point gets lifted at the start of animation and settles down at the end of animation.
First define the point for the bottom left corner...
CGPoint bottomLeft = CGPointMake(0, 480); // this can be anything.
Then you need to define the sizes (big and small).
CGSize bigSize = CGSizeMake(280, 280);
CGSize smallSize = CGSizeMake(50, 50); // again, these can be anything.
Then animate them...
// create the rect for the frame
CGRect bigFrame = CGRectMake(bottomLeft.x, bottomLeft.y - bigSize.height, bigSize.width, bigSize.height);
CGRect smallFrame = CGRectMake(bottomLeft.x, bottomLeft.y - smallSize.height, smallSize.width, smallSize.height);
[UIView animateWithDuration:0.2
animations:^{
// set the rect onto the view
bottomLbl.frame = bigFrame;
// or
bottomLbl.frame = smallFrame;
}];
As long as you set the frame and the calculated end frames are correct and it's all done in one animation then the bottom left corner won't move.
If this doesn't help can you please post a video of what is happening (and all your animation code).
EDIT
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
// set the rect onto the view
bottomLbl.frame = bigFrame;
// or
bottomLbl.frame = smallFrame;
}
completion:nil];

UILabel always animates to same spot

I have a UILabel called "nameLabel" and I have it inside an animation block so that this happens:
_nameLabel.alpha = 1;
CGAffineTransform translate = CGAffineTransformMakeTranslation(50, 50);
_nameLabel.transform = translate;
I thought that animates the UILabel to the spot I specify but it just animates from the above spot to the place where I have it in the Interface Builder. Any help here?
Can you post the animation block and other associated code? I am not sure what CGAffineTransformMakeTranslation does with the label, but if you want to animate the frame location, you can use this:
CGRect frame = _nameLabel.frame;
frame.origin.y = 100; //Desired height, origin.x can be modified as well.
//You can also change the frame size here but it wont work on UILabels, you will need `CGAffineTransformScale` for that.
[UIView animateWithDuration: 1.5
delay:0.0
options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState
animations:^ {
[_nameLabel setFrame:frame];
}
completion:^ (BOOL finished) {
}];
Edit: The other way:
CGRect frame = _nameLabel.frame;
frame.origin.y = 100;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.5];
[_nameLabel setFrame: newFrame];
[UIView commitAnimations];
Current state is probably the current location of the label, try that first but if nothing happens, remove UIViewAnimationOptionBeginFromCurrentState or set the frame of the label to another location before the animation, and move it to its initial (the one in the xib file) position in the animation block, its your call.
Watch out because Autolayout cause a lot of problems.
Try to deselect 'Use Autolayout'
It solves to me all the problems trying to translate objects.

Resources