I'm trying to move and resize a label, but what happens is the label resizes immediately then moves into position. I first tried simply the commented out lbl.frame line. Next I found this question:
How to animate while resizing UIView
And added all the other code except for the contentMode. This did what I wanted, but the Label's font did not adjust downwards as the label shrunk. ( I tick adjust to fit in xib ). Finally adding the contentMode line gave me the same result as my original frame line - shrink immediately first them animate the move.
lbl.contentMode = UIViewContentModeRedraw;
[UIView animateWithDuration:1.0 delay:0.0
options:(UIViewAnimationOptionAllowUserInteraction)
animations:^{
//lbl.frame = CGRectMake(x, mStartingLine.frame.origin.y+mStartingLine.frame.size.height, 100, 100);
CGRect theBounds = lbl.bounds;
CGPoint theCenter = lbl.center;
theBounds.size.height = 100;
theBounds.size.width = 100;
theCenter.y = mStartingLine.frame.origin.y+mStartingLine.frame.size.height+50;
theCenter.x = x;
lbl.bounds = theBounds;
lbl.center = theCenter;
}
completion:nil
];
I suspect that the auto text resizing feature doesn't work with Core Animation.
What I would suggest doing is to set the label to it's final size (using it's bounds) then apply a transform to it that shrinks it back down to it's starting size. The end effect of those things is that it should stay at the same apparent size.
Finally, use animateWithDuration:animations: to set the view's transform back to the identity transform, so it grows to it's new size.
I don't know what drawing artifacts this will cause - you'll have to try it.
Related
I would like to know if there is a way to change a label's frame's width (not the fontSize or something) with a smooth animation.
I already tried the following, that did (obviously) not work:
_myLabel.frame = CGRectMake(139,193,42,21);
[UIView animateWithDuration:1 animations:^ {
_myLabel.frame = CGRectMake(139, 193, 100, 21);
} completion:^(BOOL finished) {
}];
So what basically happened after running this code was that it changed the width as expected but without any animation.
Any ideas?
You can't change the frame size of labels...
You can reach correct animation behavior.. set label.contentMode = UIViewContentModeCenter but it looks ugly
But you can...:
change is the bounds, rather than the frame https://stackoverflow.com/a/3304220
add an UIView and then add UILabel as its subview and animate UIView https://stackoverflow.com/a/15639093 and https://stackoverflow.com/a/22224630
Use a CGAffineTransform to do this but have some ugly side effects like distorting the text on the label https://stackoverflow.com/a/13066366
change the font of UILabel with transform Animation Animating UILabel Font Size Change
What I'm trying to reach is similar to what is implemented on youTube app on iPad. The search field is expanding in animation from right to left. I'm trying to do so and i'm getting very strange and not smooth animation, Although left to right is working perfect.
|<-------------------------------|Search Field|
It seems that the origin value is changed first and than the width changed , un like the left-right expanding animation that the origin stays the same.
Thanks
You can use animation just put Search field in dynamically in view and put below code.
[UIView beginAnimations : #"Display notif" context:nil];
[UIView setAnimationDuration:0.30];
[UIView setAnimationBeginsFromCurrentState:FALSE];
CGRect frGnrVw = generalView.frame;
CGRect frTblNote = tblNotes.frame;
frGnrVw.size.height = 0.0;
frGnrVw.size.height += 78.0;
generalView.frame = frGnrVw;
[UIView commitAnimations];
In above code general view is my view which has hight 0 and when some action called at that time view height increase and and we will see that view expanding down in that i can not change view's x and y position But in your case first hide your view and when search action calls set hidden NO of your view and in my code i increase height so you can increase your width and also change it's x position means (decrese) i.e you increase width 320 than you decrese it x position to 320 .
just try it it will work.
you can also put it statically in your story board or in nib just set its width =0 and x= 320.
you have to do like below.
[UIView beginAnimations : #"Display notif" context:nil];
[UIView setAnimationDuration:0.30]; // set duration of animation in seconds.
[UIView setAnimationBeginsFromCurrentState:FALSE];
CGRect frGnrVw = generalView.frame; //get frame of view.
frGnrVw.size.width = 0.0;
frGnrVw.size.width += 320.0;//increase width.
frGnrVw.origin.x -=320.0; // decrese position.
generalView.frame = frGnrVw; //set new frame to view.
[UIView commitAnimations]; // this will require.
you just put your view with search field at the position x=320 ,y = as your requirement ,width = 0 and height = as your requirement.
try it it will work.
Also you can hide like same in reverse order.
means increase its x position and decrease its width with above code.
If my answer helps than please vote up my answer.
I have an animation which is kicked off when a gesture recogniser (double tap) fires:
[UIView animateWithDuration:0.3 animations:^{
_scrollView.contentOffset = CGPointMake(x, y);
_scrollViewContentView.frame = someFrame;
_scrollViewContentView.layer.transform =
CATransform3DMakeScale(1.f/_zoomScale, 1.f/_zoomScale, 1.f);
}];
It's working nice except in one case : if scrollViewWillBeginDecelerating delegate method is not called before animation execution (just by dragging hardly my scrollview).
I just have scrollViewDidEndDragging method called.I can wait 20 sec and then play my animation. It'll play correctly except for my contentOffset.
The delegate methods themselves do nothing, they were only added to see where the problem might be.
I have no idea why.
Edit : here's a video of my problem. Phase 1 : scroll with deceleration and phase 2 without. Look a the final position. Phase 1 is correct but not phase
try:
[_scrollView setContentOffSet:CGPointMake(x, y) animated:YES];
outside of the animation block. I don't believe contentOffSet is animatable through UIView's animation block.
Edit:
Instead of:
_scrollview.contentOffSet = CGPointMake(x, y);
try:
_scrollview.bounds = CGRectMake(x, y, CGRectGetWidth(scrollview.bounds), CGRectGetHeight(scrollview.bounds));
I suspect that x in this line may be causing the effect that you see:
_scrollView.contentOffset = CGPointMake(x, y);
What's it's value? I think you should try replacing that by CGPointMake(0, y) and see if that causes the white margin to appear every time.
My reasoning is the following:
1) to create bouncing effect that doesn't go outside the scope of the image (doesn't show white background), you must have set _scrollView's contentSize.width less than the actual image size.
2) to allow some scrolling you have set the contentSize.width greater than the width of the _scrollView
3) you have centered the image within the _scrollView relatively to the size of it's contentSize
4) when animating you are probably setting frame with pre-calculated x coordinate to position the image on the left size because without that CATransform3DMakeScale would just leave the image in the center (by the way, why use CATransform3DMakeScale, when you could just change the size in the frame?)
5) in the video, when running the animation the first time, you have contentOffset.x to it's maximum value (because you drag to the left therefore increasing the content offset and scrollview bounces back to it's max content offset that doesn't go beyond content size limits)
6) in the video when running the animation for the second time, you have contentOffset.x with a smaller value because you drag to the right by decreasing it
7) when animation is finished, you still have the same content size for your scrollView and therefore the same amount of scroll available. If you have the contentOffset.x at it's maximum value then image will be more on the left, if you have contentOffset.x with less value - image will be more on the right
8) if the x in _scrollView.contentOffset = CGPointMake(x, y); is related to actual content offset prior to animation then that makes sense that the image appears more on the left in the first case and more on the right in the second case.
If I'm right then this is how you could solve it:
a) If you want the image always to appear on specific x position, make sure to set constant contentOffset in the animation.
b) Adjust the code of calculating frame (someFrame) origin according to the contentOffset that you'll be animating to (looks like now it works only with the maximum contentOffset.x).
c) If after animation you don't want the content to be scrollable, make sure to set _scrollView.contentSize = _scrollview.bounds.size; in the animation block.
I'm not sure I completely understand your problem (Maybe you can try to explain what you want to accomplish in this animation?). Any way, maybe try this instead of using setContentOffset:
CGRect *rect = CGRectMake(x, y, 0, 0);
[_scrollView scrollRectToVisible:rect animated:YES];
Perhaps try using core animation rather than UIView animations. It won't make a difference if the reason you're running into trouble is because all animations are being removed from the layer, but if it's due to -[removeAnimationForKey:#"bounds"], this might be a winner.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"bounds"];
animation.fromValue = [NSValue valueWithCGRect:_scrollView.layer.bounds];
animation.toValue = [NSValue valueWithCGRect:(CGRect){ .origin = CGPointMake(x,y), .size = scrollView.layer.bounds.size }];
[scrollView.layer addAnimation:animation forKey:#"myCustomScroll"];
scrollView.layer.bounds = (CGRect){ .origin = CGPointMake(x,y), .size = scrollView.layer.bounds.size };
P.S. I haven't tested the code above it's just off my head, so apologies for any silly errors.
According to the Apple documentation available here the bounds property of a UIView can be animated.
In order to programmatically rotate one of my views (in this case from portrait to landscape), I implemented the following code:
float w = controlsView.bounds.size.width;
float h = controlsView.bounds.size.height;
CGAffineTransform T = CGAffineTransformMakeRotation(M_PI/2);
UIViewContentMode oldContentMode = controlsView.contentMode;
controlsView.contentMode = UIViewContentModeRedraw;
[UIView animateWithDuration:1.0 animations:^{
controlsView.bounds = CGRectMake(0, 0, h, w);
controlsView.transform = T;
}];
controlsView.contentMode = oldContentMode;
I added the two instructions for contentMode because I have read somewhere on StackOverflow that contentMode must be set to that value in order for a UIView to redraw the content while the bounds property is modified (however, in this case it does not affect the behaviour in any way).
The problem of that code is that UIView is not resized with an animation but all at once.
Executing that code, the UIView is first resized (without animation) then rotated with an animation.
How can I animate the resizing?
-- UPDATE --
I tried to combine a scaling and rotating transformation. The UIView rotates and scales in an animation, but at the end its bounds property does not change: even if it has been rotated to a landscape orientation (which should be 568x320 on my iPhone), its width and height stay at the portrait values (320x568). Indeed, the UI controls on the controlsView are deformed (wrong aspect ratio) and appears stretched.
This worked for me using UIViewAnimationOptions.LayoutSubviews (Swift):
UIView.animateWithDuration(1.0,delay:0.0,
options:UIViewAnimationOptions.LayoutSubviews,
animations:{ () -> Void in
myView.transform = myRotationTransform
myView.bounds = myBounds
}, completion: nil)
(no explicit scaling nor changing contentMode)
The problem is that when you set a transform property, all other transforms (bounds) are overwritten. To fix it you have to create one transform that combines scaling and rotating.
Example:
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(0.5, 0.5);
[UIView animateWithDuration:1.0 animations:^
{
controlsView.transform = CGAffineTransformRotate(scaleTransform, M_PI/2);
}];
You will need to calculate the scaling X and Y values based on the size you want to have at the end of the animations. You might also want to change the anchorPoint property to set a center point used for scaling (controlsView.layer.anchorPoint).
Animating your bounds doesn't change its value. It reverts to its original value once the animation ends.
Change the value of the bounds to the final value once the animation is over. I'll solve the trouble.
I have a round image that I want to "squish" vertically so that it looks more like a horizontal line, then expand it back to the original shape. I thought this would work by setting the layer's anchor point to the center and then animating the frame via UIViewAnimation with the height of the frame = 1.
[self.imageToSquish.layer setAnchorPoint:CGPointMake(0.5, 0.5)];
CGRect newFrame = CGRectMake(self.imageToSquish.frame.origin.x, self.imageToSquish.frame.origin.y, self.imageToSquish.frame.size.width, 1 );
[UIView animateWithDuration:3
animations:^{self.imageToSquish.frame = newFrame;}
completion:nil];
But the image shrinks toward the top instead of around the center.
You’re giving it a frame that has its origin—at the top left—in the same position as it started. You probably want to do something more like this, adding half the image’s height:
CGRect newFrame = CGRectMake(self.imageToSquish.frame.origin.x, self.imageToSquish.frame.origin.y + self.imageToSquish.frame.size.height / 2, self.imageToSquish.frame.size.width, 1);
Alternatively—and more efficiently—you could set the image view’s transform property to, say, CGAffineTransformMakeScale(1, 0.01) instead of messing with its frame. That’ll be centered on the middle of the image, and you can easily undo it by setting the transform to CGAffineTransformIdentity.