How to enlarge dynamically an UILabel (label and font size)? - objective-c

Im currently working on an iPhone project. I want to enlarge dynamically an UILabel in Objective-C like this:
alt text http://img268.imageshack.us/img268/9683/bildschirmfoto20100323u.png
How is this possible? I thought I have to do it with CoreAnimation, but I didn't worked. Here is the code I tried:
UILabel * fooL = //[…]
fooL.frame = CGRectMake(fooL.frame.origin.x, fooL.frame.origin.y, fooL.frame.size.width, fooL.frame.size.height);
fooL.font = [UIFont fontWithName:#"Helvetica" size:80];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.5];
[UIView setAnimationBeginsFromCurrentState:YES];
fooL.font = [UIFont fontWithName:#"Helvetica" size:144]; //bigger size
fooL.frame = CGRectMake(20 , 44, 728, 167); //bigger frame
[UIView commitAnimations];
The problem with this code is that it doesn't change the fontsize dynamically.

All you need to do is apply an affine transform to the UILabel object.
CGFloat scaleFactor = 2.0f;
label.transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor); // Enlarge by a factor of 2.

Scaling your label as suggested by others using the transform property will work great. One thing to keep in mind is that as the label gets larger, the font is not increasing, but just the rendered text, which means it will appear "fuzzier" as it gets larger.

Just scale your Label instead of changing the fontSize.

Try this method:
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition
forView:(UIView *)view
cache:(BOOL)cache
Parameters:
transition
A transition to apply to view. Possible values are described in UIViewAnimationTransition.
view
The view to apply the transition to.
cache
If YES, the before and after images of view are rendered once and used to create the frames in the animation. Caching can improve performance but if you set this parameter to YES, you must not update the view or its subviews during the transition. Updating the view and its subviews may interfere with the caching behaviors and cause the view contents to be rendered incorrectly (or in the wrong location) during the animation. You must wait until the transition ends to update the view.
If NO, the view and its contents must be updated for each frame of the transition animation, which may noticeably affect the frame rate.
Discussion
If you want to change the appearance of a view during a transition—for example, flip from one view to another—then use a container view, an instance of UIView, as follows:
Begin an animation block.
Set the transition on the container view.
Remove the subview from the container view.
Add the new subview to the container view.
Commit the animation block.

Related

Get current frame of UIView while animated

I have a UIView and I want to get it's current frame while it's animated.
I am using a basic animation:
[UIView beginAnimations:#"MoveView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:3];
_testView.frame = CGRectMake(0, 100, 40, 40);
[UIView commitAnimations];
and I have a button which should add another UIView at the current position of the first one while animated, but when I press the button, it adds it to the end position of the animation...
Any suggestions?
Thank you in advance!
Most probably you're setting the newly added UIView properties based on the animated view's modelLayer. Let's try to setup the UIView properties based on the animated view's presentationLayer:
The layer object returned by this method provides a close approximation of the layer that is currently being displayed onscreen. While an animation is in progress, you can retrieve this object and use it to get the current values for those animations.
CALayer Class Reference

Animate intrinsicContentSize changes

I have a UIView subclass that draws a circle whose radius changes (with nice bouncy animations). The view is deciding the size of the circle.
I want this UIView subclass to change its frame size to match the animated changes to the circle radius, and I want these changes to modify any NSLayoutConstraints connected to the view (so that views that are constrained to the edge of the circle will move as the circle resizes).
I understand that implementing -(CGSize)intrinsicContentSize and calling invalidateIntrinsicContentSize when the radius changes will tell constraints to update, but I cant figure out how to animate the changes to intrinsicContentSize.
Calling invalidateIntrinsicContentSize from within a [UIView animateWith... block just instantly updates the layout.
Is this even possible, and is there a workaround/better approach?
invalidateIntrinsicContentSize works well with animations and layoutIfNeeded. The only thing you need to consider is, that changing the intrinsic content size invalidates the layout of the superview. So this should work:
[UIView animateWithDuration:0.2 animations:^{
[self invalidateIntrinsicContentSize];
[self.superview setNeedsLayout];
[self.superview layoutIfNeeded];
}];
Swift version of #stigi's answer which worked for me:
UIView.animate(withDuration: 0.2, animations: {
self.invalidateIntrinsicContentSize()
self.superview?.setNeedsLayout()
self.superview?.layoutIfNeeded()
})
Width / height constraint doesn't help? Keep reference of this constraint and ...
[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:myViewInitialWidth];
... when you do want to animate myView resize, do this ...
self.viewWidthConstraint.constant = 100; // new width
[UIView animateWithDuration:0.3 animations:^{ [view layoutIfNeeded]; }];
... do the same thing for the height.
Depends on your other constraints, maybe you will be forced to raise priority of these two constraints.
Or you can subclass UIView, add - (void)invalidateIntrinsicContentSize:(BOOL)animated and fake it by yourself. Get new size from - (CGSize)intrinsicContentSize and animate it by animating width / height constraints. Or add property to enable / disable animations and override invalidateIntrinsicContentSize and do it inside this method. Many ways ...
In the code below, intrinsic class is the class that has just changed it's size on changing a variable. To animate the intrinsic class only use the code below. If it impacts other objects higher up the view hierarchy then replace self.intrinsic class with the top level view for setNeedsLayout and layoutIfNeeded.
[UIView animateWithDuration:.2 animations:^{
self.intrinsicClass.numberOfWeeks=8;
[self.intrinsicClass setNeedsLayout];
[self.intrinsicClass layoutIfNeeded];
}];
None of this has worked for me. I have a UILabel which I am setting with a NSAttributedString. The text is multiline and wrapping on word boundaries. Therefore the height is variable. I've tried this:
[UIView animateWithDuration:1.0f animations:^{
self.label = newLabelText;
[self.label invalidateIntrinsicContentSize];
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
And a number of variations. None work. The label immediately changes it's size and then slides into it's new position. So the animation of the labels position ons screen is working. But the animating of the label's size change is not.
Well for Swift 4/3 this works and I think this is best practise. If you have a UIView with a UILabel in it and the UIView adapts the frame from the UILabel, use this:
self.theUILabel.text = "text update"
UIView.animate(withDuration: 5.0, animations: {
self.theUIView.layoutIfNeeded()
})
The normal self.view.layoutIfNeeded() will work most of the time as well.

Animating contentInset to UITableView also animates rows' subviews' frames

I have a UITableView with custom cells. Naturally, in cellForRowAtIndexPath I try to dequeue an old cell and reuse it. Each cell has a hierarchy of autoresized views: I set the frame of the top view when I set its content in cellForRowAtIndexPath, and its subviews change their frames accordingly. Note that row height is dynamic too.
It all works nice when I just scroll the table (with the rows of different content and frames). But I also have a text field in the same view as this table, so I need to scroll the table's contents to compensate the keyboard being shown/hidden. I animate contentInset property for that:
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
NSTimeInterval animationDuration = [[aNotification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
UIViewAnimationCurve animationCurve = [[aNotification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
[UIView setAnimationCurve:animationCurve];
[UIView animateWithDuration:animationDuration animations:^{
messagesTable.contentInset = UIEdgeInsetsMake(0, 0, kHSTableBottomInset, 0);
messagesTable.scrollIndicatorInsets = UIEdgeInsetsZero;
}];
}
It works good as well, but there's an interesting glitch: when keyboard is hidden and contentInset is animated back to normal (kHSTableBottomInset is a small value to keep margin), table reloads the cells that will scroll from above to be displayed. The problem is that this reloading is done inside the animation block too! As a result, when I change the dequeued subview frame (specifically, width) in cellForRowAtIndexPath (which is called as a part or reloading), this change is animated too and it's visible as the cell scrolls down to view.
Can I avoid such behavior?
I finally found the solution: frame-setting code can be excluded from animation like this:
[CATransaction begin];
[CATransaction setDisableActions:YES];
mainDataView.frame = rect;
[CATransaction commit];
or
[UIView setAnimationsEnabled:NO];
mainDataView.frame = rect;
[UIView setAnimationsEnabled:YES];
Found the answer here: How can I exclude a piece of code inside a core animation block from being animated?
Solved this issue by setting clipsToBounds YES to tableview.
tableView.clipsToBounds = YES:
And if you still have issues, set clipsToBounds to footerview also.

How can I animate a change to a UIButton's height without image warping?

I'm using [UIView animateWithDuration:animations:] to hide a UIButton by changing its frame.size.height to 0. However, as soon as the animation begins, the rounded rectangle and background immediately disappear while the button text clips off the bounds of the view.
The code I'm using is fairly straightforward:
CGRect newFrame = button.frame;
newFrame.size.height = 0;
[UIView animateWithDuration:2.0 animations:^{
button.frame = newFrame;
}];
I've noticed that this only happens when i'm setting the height to 0. It seems that when the animation begins, the button is simply redrawn once in its final state. The animation is performed by scaling this static image from the original size to the final one. Since a button with a height of 0 can't be seen, it results in the whole roundrect disappearing (except for the text on the button, since it's a different view).
There must be a better way to do this so the animation doesn't look as weird. How can I make the animation behave the way I want?
Does it work better if you do something like this?
CGRect newFrame = button.frame;
newFrame.size.height = 1;
[UIView animateWithDuration:2.0
animations:^{button.frame = newFrame;}
completion:^{button.hidden = YES;}];
If you are using a system rounded rect button, it might also be that they do not like being resized below a certain level, it might work better with a custom button.
Why not just setting your button's alpha value to 0 in your animation? Or do you have to animate its height?
Take an image snapshot of the button, and do an affine transform animation rotating that view upwards, or changing the y scale.

UIColor groupTableViewBackgroundColor is transparent

I have a grouped style UITableView on my navigation stack, and when I click on a cell, I push a UIDatePicker onto the stack. The problem is that I want this custom view to have the same background color as my table view.
I tried setting the background color of my custom view like:
datePicker.backgroundColor = [UIColor groupTableViewBackgroundColor];
But this comes out transparent. I also tried modifying the underlying CGColor object to have an alpha of 1.0, which caused the background color to be black.
The following does work as expected:
datePicker.backgroundColor = [UIColor lightGrayColor];
But, of course, this color doesn't quite match the grouped table background color.
Am I going about this all wrong? I found a similar post about this here, but no helpful response.
What do you mean you "push a UIDatePicker onto the stack"? Why dont you try animating the UIDatePicker into view?
when the view loads, create the picker and set the frame off screen, such as
[picker setFrame:CGRectMake(0,960,320,216)];
then instead of "pushing" the picker, animate it into view like:
[UIView beginAnimations:nil context:NULL];
[picker setFrame:CGRectMake(0,200,320,216)];
[UIView commitAnimations];
And when you want to dismiss the picker, just hide it like:
[UIView beginAnimations:nil context:NULL];
[picker setFrame:CGRectMake(0,960,320,216)];
[UIView commitAnimations];
If you need to, you can also add a toolbar with a "done" button to dismiss the picker, works great for me.
If the contents of the picker are going to be displayed on the table, then you can set the frame of the table in that animation sequence. in the first one, make the table half the size (like 150 for my example would work perfect), then in the hide sequence, make the table the original size (415 for this example). And when you hide the picker, call [tableView reloadData]; to refresh the table.