I have question about artifacts that appear when UITextField is moving in animation block...
Before i move my UITextField it looks like this:
and after moving like this:
My guess is that it has something to do with fonts after UITextField is shifted.
here's code that i use for moving UITextField:
if (answerText.editing)
{
[UIView beginAnimations:#"Moving UITextField" context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:1.0];
movingAnswer = CGPointMake(160,75);
answerText.center = movingAnswer;
[UIView commitAnimations];
}
It could be that the resulting frame isn't aligned on an even integer. i.e. Moving that amount is causing the frame to be something like (100.5, 50.0, 50.0, 50.0). When you are drawing on a half-pixel boundary, some of the drawing routines are going to make things look blurry to try and make it appear in the correct place. I would print out the frame after the animation and check:
NSLog(#"%#", NSStringFromCGRect(movingAnswer.frame));
If you see any non-integer values, use one of the floor() functions to modify the resulting frame in order to snap it to a boundary.
Related
I have a tableView with textFields inside of them, and I have animation that slides the tableView up when the textFieldDidBeginEditing method is called. Here is my code:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.headerView.alpha = 0.2;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.18];
[UIView setAnimationDelegate:self];
self.theTableView.frame = CGRectMake(0, 130, 320, 209);
[UIView commitAnimations];
}
The problem is that the animation happens whenever one of the cells is tapped, but I only want it to happen the first time a cell is tapped. So I was thinking that I should make an if statement that checks whether the tableView is at the (0, 130) coordinates. Does anyone know how I would do this?
For an exact comparison, CGPointEqualToPoint() will suffice. For a broader comparison (checking if the rect of the view contains the given point), CGRectContainsPoint() is perfect.
Of course, all of this is a little much. Subclass your view and keep a flag on it to track whether or not they've been slid up. Not only does it keep your code more self-contained, but it keeps the logic for the view out of your controller.
I am trying to move a UIView programmatically using the following method:
-(void)animatePlaybackLine: (int) currentBeat{
CGRect newFrame = CGRectMake(currentBeat*eighthNoteWidth, 0, eighthNoteWidth, 320);
[playbackLine setFrame:newFrame];
NSLog(#"Line animated to %i", currentBeat);
NSLog(#"New frame origin %f", playbackLine.frame.origin.x);
}
When the method is called, the NSLogs show that the variable currentBeat is incrementing as it should, and the frame of playbackLine (my UIView) appears to be moving as it should. However, the object on the screen doesn't move. I have also tried setting the bounds and the center instead of the frame, and all of them have similar results. I also tried using an animation instead of setting the frame, to no avail.
Is there something else I should be doing to make the image onscreen show the changing frame?
I'm guessing you're calling that method in a loop? iOS isn't going to redraw the screen until your code finishes executing. You can't loop like this and see iterative results.
To animate views, you should use the native support UIKit gives you. In particular, check out the Animations section in the UIView class reference.
Try this
[UIView animateWithDuration:0.3
delay:0.0
options: UIViewAnimationCurveEaseOut
animations:^{
datePickerView.frame = imageFrame;
}
completion:^(BOOL finished){
self.datePickerViewFlag = NO;
}];
Edited to better explain my problem
I am trying to perform a zoom operation using my custom view (not UIView). The view has translation, scale, rotate values. I use these as follows, between calls to glPushMatrix() and glPopMatrix().
- (void)transform
{
glTranslatef(translation.x + anchor.x, translation.y + anchor.y, 0.0f);
//glRotatef(-rotation * 57.2957795f, 0.0f, 0.0f, 1.0f);
glScalef(scale.x, scale.y, 1.0f);
glTranslatef(-anchor.x, -anchor.y, 0.0f);
}
I am trying to figure out how I should modify the anchor and/or translation values so that the zoom operation is relative to what appears on screen. At 1:1 scale I can simply use the raw screen coordinates as the anchor and perform the above transform. But when the view is already at some arbitrary scale/position, the anchor and/or translation needs to account for that.
So far this is what I've figured out:
1) Get the displacement from the center of scale to the view origin, in screen coordinates.
2) Scale this value so it's in the view's local coordinate system.
3) Now I have the new anchor for scaling. I set the view's anchor to this value.
This alone is not enough it seems. I think I am missing a translation component, or another variable that goes into the new anchor point. What am I missing?
I found a solution. I used a separate transform specifically for the zoom operation, in addition to the transform that defines the original view. I simply concat the two to get the result I wanted -- which was to ensure that the zoom is relative to the original view.
Some of the CGAffine animations make assumptions about the components of the matrix that you wouldn't expect.
For example,i found that CGAffineTransformMakeTranslation also effected the rotation of the View. For this reason i would recommend not using the 'Make' transforms if your concating many instances of CGAffineTransform
Also, in your above example i can see that you assume that your matrix understands that your two translates should occur at different times. A transform matrix is is a set of physical attributes about the object at any 1 point in time.
You want an object to move to -anchor
and scale
You want an object to move to back to
anchor
These should be considered as two different animations
You should do this with 'Key Frame Animation', here is an example: CGPath Animation
Alternatively, you could chain two CGAffineTransform methods together.
-(void)Anim1
{
[UIView beginAnimations:#"Anim1_Done" context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
//DO STUFF HERE
[UIView commitAnimations];
}
- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context
{
if ([animationID isEqualToString:#"Anim1_Done"])
{
[self Anim2];
}
}
-(void)Anim2
{
[UIView beginAnimations:#"Anim2_Done" context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
//DO STUFF HERE
[UIView commitAnimations];
}
Your transform intent still isn't exactly clear.
The CGAffineTransformMakeTranslation transform will create the translation matrix needed to get to a desired point, but as i mentioned in my other answer some of the make transforms make assumptions about other things like rotation, if your object hasn't been rotated and therefore cant be reset then this isn't a problem, other wise you can use the translation components of the matrix:
Transform.tx;
Transform.ty;
Edit: 3 separate animations should be done with 3 separate matrices:
baseMatrix = CGAffineTransformIdentity;
affineMatrix1 = CGAffineTransformTranslate(baseMatrix, -anchor.x, -anchor.y);
affineMatrix2 = CGAffineTransformScale(baseMatrix, scale.x, scale.y);
affineMatrix3 = CGAffineTransformTranslate(baseMatrix, anchor.x, anchor.y);
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.
I'm trying to transform a UISearchBar, like in Mobile Safari: touch in the search field and it grows while the location field shrinks.
My current animation to alter the width and position of the search field only animates the position: just before it slides to the right place, it simply snaps out to the right width. Here's my code:
[UIView beginAnimations:#"searchGrowUp" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationDelegate:self];
CGFloat findFieldWidth = findField.frame.size.width;
CGFloat urlFieldWidth = urlField.frame.size.width;
CGRect findFieldFrame = findField.frame;
CGRect urlFieldFrame = urlField.frame;
findFieldFrame.origin.x = findFieldFrame.origin.x - 150.0f;
findFieldFrame.size.width = findFieldWidth + 150.0f;
urlFieldFrame.size.width = urlFieldWidth - 150.0f;
urlField.frame = urlFieldFrame;
findField.frame = findFieldFrame;
[UIView commitAnimations];
I've modified this code slightly for the sake of presenting it here, but I hope this gives the gist.
Any guesses as to why this is happening would be appreciated!
Cheers,
Aaron.
I figured it out thanks to this post: Changing the size of the UISearchBar TextField?
Turns out the contents of a UISearchBar don't resize properly along with the outer layer. So you have to call -layoutSubviews: within the animation block after the frame is set on the searchbar. So the block ends like:
[findField setFrame:CGRectMake(findField.bounds.origin.y, findField.bounds.origin.y, findFieldWidth, findField.bounds.size.height)];
[findField layoutSubviews];
[UIView commitAnimations];
Props to Nick Farina!
I had the same problem when trying to animate the width of a UISearchBar.
On iOS 4 and later, I found that using UIViewAnimationOptionLayoutSubviews as an option for
+[UIView animateWithDuration:delay:options:animations:completion:]
fixed it.
The accepted answer works but according to Apple docs you "should not call this method". The clean solution is to use layoutIfNeeded method:
[UIView animateWithDuration:UINavigationControllerHideShowBarDuration
delay:0.f
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
[searchBar setFrame: ...
[searchBar layoutIfNeeded];
...
Enjoy!
Sorry this is a bit old, but I was running into a similar problem.
I didn't want to use layoutSubviews because the documentation says you shouldn't call that method directly.
What I did to solve my problem was call sizeToFit on the subview within the animation block.