I am trying to animate the UISearchBar using the
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
delegate methods, but my implementation of the latter seems to lead to a clumsy animation (slow animation version here). My delegate implementation is shown below (I changed the duration to generate the second video). Is there any way to fix this?
It may be important to note that navigation is a standalone UINavigationBar (I did not use a UINavigationController for this).
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
[UIView animateWithDuration:.25
delay:0.0
options: UIViewAnimationOptionBeginFromCurrentState
animations:^ {
navigation.alpha = 1;
CGRect newTableBounds = chatList.frame;
newTableBounds.size.width -= 40; //newBounds.size.width -= 215; to contract
newTableBounds.origin.x += 40;
newTableBounds.origin.y += 40;
chatList.frame = newTableBounds;
CGRect rootFrame = self.ddParent.rootViewController.view.frame;
rootFrame.origin.x += 40;
self.ddParent.rootViewController.view.frame = rootFrame;
}
completion:nil];
return YES;
}
You aren't adjusting the search bar frame within the animation. The adjustment is taking place immediately, and then the other items are animated. Move it into the animation block, and everything should be good.
Related
I have a view controller which adds a UIPageViewController to a subview (let's call it "overlay") programmatically. Since the page view controller's pages each have a different height, I added an NSLayoutConstraint on the "overlay" subview.
On every swipe I calculate the height of the upcoming view controller and resize the overlay view accordingly:
- (void)resizeOverlayToBottomOf:(UIView *)element {
// resize overlay in parent view controller so it shows the element
float bottomOfElement = element.frame.origin.y + element.frame.size.height + 20;
[self.parentViewController.overlayHeightConstraint setConstant:bottomOfElement];
[self.parentViewController.overlayView setNeedsUpdateConstraints];
[self.parentViewController.overlayView setNeedsLayout];
[self.parentViewController.overlayView layoutIfNeeded];
}
Everything works as expected... until I want to change the overlay size with an animation.
I wrapped the last two lines of the above method with an animation block:
[UIView animateWithDuration:0.25f animations:^{
[self.parentViewController.overlayView setNeedsLayout];
[self.parentViewController.overlayView layoutIfNeeded];
}];
Now after a swipe completes, the height of the overlay view changes with an animation.
The Problem is that while the animation plays, the page view controller's content snaps back to some place off screen and swipes back in. I tried adding constraints to ensure a fixed width of the page view controller content, but nothing seems to do the trick.
Any hint on how to animate the parent view without affecting the page view controller views will be highly appreciated!
I recently had the same problem. This apparently works:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
if (completed)
{
CGFloat height = [self calculateHeight];
[CATransaction begin];
[CATransaction setCompletionBlock:^{
self.heightConstraint.constant = height;
[UIView animateWithDuration: 0.25
delay: 0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
}];
}];
[CATransaction commit];
}
}
My understanding is that one animation interferes with the other.
CATransaction intercepts the current animation and will do it's completion block after the current animation is done.
This works fine for me.
Well, this bit of code did the trick:
[UIView animateWithDuration:0.25f animations:^{
// [self.parentViewController.overlayView setNeedsLayout];
// [self.parentViewController.overlayView layoutIfNeeded];
CGRect frame = self.parentViewController.overlayView.frame;
frame.size.height = bottomOfElement;
self.parentViewController.overlayView.frame = frame;
}];
The funny thing is, it does not seem to matter what value I use for frame.size.height, the constraint seems to be put in currently anyway.
If someone could explain why this works, I'd be delighted.
Im dynamically creating textFields on UIScrollView, I'm animating View to bring textField above the keyboard if keyboard is hiding it. To animate View is used code given below:
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect textFiledFrame = textField.frame;
if (textFiledFrame.origin.y > 219 && textField.tag > 150 && viewAnimated == 0) {
CGRect superViewFrame = textField.superview.frame;
superViewFrame.origin.y = superViewFrame.origin.y - 120;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.6];
[textField.superview setFrame:superViewFrame];
[UIView commitAnimations];
viewAnimated = 1;
}
}
for every single time i'm clicking on textFields textFieldDidBeginEditing:(UITextField *)textField is being call but once view get animated, textFieldDidBeginEditing:(UITextField *)textField is not being called
There are several things wrong with your code:
You should not hardcode any keyboard related sizes. Instead make use of the keyboard information the iOS framework provides you (see e.g. here: How to make a UITextField move up when keyboard is present?)
You do set ViewAnimated = 1 in your if statement - do you ever rest it to 0? If not, the if statement will never be entered again, as you check on ViewAnimated == 0 in the if clause ...
Variables should not start with a capital letter (Rect, ViewAnimated) - better is textRect en viewAnimated
i am new to IOS programming. i have a background image on my screen. What i want is when app launches screen shows with the background image and then after 1 sec 2 buttons comes up from right side of the screen. how can i do this. here is the image what i am trying to do
button 1 and button2 have to be invisible first. after 1 second they comes up from right side.
if there are any tutorials related to this kind of animation then please share
You can use simple UIView Animations to achieve this.
Set your button x origin any value greater than screen size so that it is not visible first. Then reset the button frame to a visible value with view animation. For example call the following function in your viewWillAppear: method.
- (void) animateButton {
// Setting button origin to value greater than the view width.
CGRect frame = button.frame;
frame.origin.x = self.view.frame.size.width+10;// or set any value > 320
button.frame = frame;
[UIView animateWithDuration:0.5
delay:2.0
options: UIViewAnimationCurveEaseOut
animations:^{
button.frame = CGRectMake(20, 100, 60, 25) ;// Any value according to your requirement
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}
Refer Tutorial
You can do it this way, please note that, if you want to animate the way your button shows up, you must hide them using alpha = 0.0f (and not hidden = true). This way, you will have a smooth showing up animation !
Here it is :
First, on your viewDidLoad of your UIViewController, you have to set up a NSTimer of 1sec, then let it call the method that will let your buttons appear :
- (void) viewDidLoad {
[super viewDidLoad];
// Do your init stuff here
// We will call your buttons as if they are declared as properties of your class, ask if you don't know how to set them
self.button1.alpha = 0.0f;
self.button2.alpha = 0.0f;
// This will wait 1 sec until calling showButtons, where we will do the trick
NSTimeInterval timeInterval = 1.0;
[NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:#selector(showButtons) userInfo:nil repeats:NO];
}
- (void) showButtons {
[UIView beginAnimations:#"buttonShowUp" context:nil];
[UIView setAnimationDuration:0.5]; // Set it as you want, it's the length of your animation
self.button1.alpha = 1.0f;
self.button2.alpha = 1.0f;
// If you want to move them from right to left, here is how we gonna do it :
float move = 100.0f; // Set it the way you want it
self.button1.frame = CGRectMake(self.button1.frame.origin.x - move,
self.button1.frame.origin.y,
self.button1.frame.size.width,
self.button1.frame.size.height);
self.button2.frame = CGRectMake(self.button2.frame.origin.x - move,
self.button2.frame.origin.y,
self.button2.frame.size.width,
self.button2.frame.size.height);
// If you want to set them in the exact center of your view, you can replace
// self.button1.frame.origin.x - move
// by the following
// (self.view.center - self.button1.frame.size.width/2)
// This way, your button will be centered horizontally
[UIView commitAnimations];
}
Ask if you have any questions !
Set the buttons' x co-ordinates such that the button is just outside the screen on the right side.
And then try the following in your viewDidLoad()
[UIView animateWithDuration:0.5
delay:1.0
options:NO
animations:^{ change your button x co- ordinate here to the co-ordinate you need it on finally}
completion:NULL];
I have a video player that has a standard toolbar. The toolbar is dismissed by a swipe down gesture. I also have a view (a panel really) that can appear directly above the toolbar and is also dismissed by a swipe down gesture. When both the panel and the toolbar are open, one swipe down gesture should dismiss the panel, a second will dismiss the toolbar. Problem is that when the swipe gestures occur quickly back-to-back (before the panel animation completes) then the toolbar animation jitters.
- (void)handleSwipe:(UISwipeGestureRecognizer *)gestureRecognizer
{
UISwipeGestureRecognizerDirection direction = [gestureRecognizer direction];
if (direction == UISwipeGestureRecognizerDirectionDown) {
if (![toolbar isHidden]) {
// Only dismiss the bottom panel if it is open
if (_selectedSegmentIndex != UISegmentedControlNoSegment) {
_selectedSegmentIndex = UISegmentedControlNoSegment;
[bottomPanelView dismissPanel];
} else {
CGRect tempRect = CGRectMake(0, self.view.frame.size.height, toolbar.frame.size.width, toolbar.frame.size.height);
[UIView animateWithDuration:0.25f
animations:^{
// Move the toolbar off the screen.
toolbar.frame = tempRect;
}
completion:^(BOOL finished) {
[toolbar setHidden:YES];
}];
}
}
}
}
[bottomPanelView dismissPanel] is in a separate class and is not aware of the class that calls it. It has the follow animation...
[UIView animateWithDuration:self.panelAnimationDuration
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
// slideOutLocation is off the screen
self.view.frame = slideOutLocation;
}
completion:^(BOOL finished) {
[self.view removeFromSuperview];
[self removeFromParentViewController];
self.panelActive = NO;
}];
So basically, the dismissPanel animation is still running when the animation to dismiss the toolbar begins. When performing a double swipe in slow motion in the simulator, the first animation looks fine, but the toolbar animation is jittery.
I know how to nest animations in the completion block, but that cannot be done here since dismissing both the panel and the toolbar is not always what is wanted. Also, the dismissPanel code is handled elsewhere and is not in control of the toolbar.
Is there a way to allow multiple animation blocks to run simultaneously without putting the completion block? Let me know if any clarification is needed! Thanks!
I wonder if the problem might have to do with auto layout (setting frames while auto layout is on causes problems). I tried a simple test of animating a view and a tool bar off the bottom of the screen by animating their constraint constants, and the animation looked fine. I made IBOutlets to their respective bottom constraints (called viewBottomCon and toolBarBottomCon).
- (void)viewDidLoad {
[super viewDidLoad];
self.isFirstSwipe = YES;
}
-(IBAction)downSwipe:(UISwipeGestureRecognizer *)sender {
if (self.isFirstSwipe) {
self.viewBottomCon.constant = -52;
self.isFirstSwipe = NO;
[UIView animateWithDuration:5 animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}else if (!self.isFirstSwipe) {
self.toolBarBottomCon.constant = -44;
[UIView animateWithDuration:3 animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
}
This is a simpler setup than yours, but I think it should work in your case too.
I subclasses UIButton to create my own UIRoundButton. I'm trying to animate a custom property called radius. It does change, but it does immediately. I tried to increase the animation duration until 5000 but the animation is still happening in a millisecond.
Here is the code:
UIRoundButton *tempItem = [self.buttons objectAtIndex:currentElement];
[tempItem setInnerColor:UIColorFromRGB(0xcdcdcd)];
currentElement = currentElement + 1;
UIRoundButton *tempItem2 = [self.buttons objectAtIndex:currentElement];
[tempItem2 setInnerColor:UIColorFromRGB(0xff0000)];
[UIView beginAnimations:#"ToggleViews" context:nil];
[UIView setAnimationDuration:5000];
tempItem.radius = 20;
tempItem2.radius = 40;
[UIView commitAnimations];
Any idea?
Implicit view animations don't work on custom properties. You have to do this at the CALayer level if you want this kind of behavior.