Programmatically scrolling UIScrollView then over-riding with manual scroll - ios

I want a scroll view to automatically scroll when the user first loads the screen... so I'm using this code:
[UIView animateWithDuration:(float)1.25f
animations:^{
myScrollView.contentOffset = CGPointMake(2000, 800);
}
completion:nil];
So the code works great and the UIScrollView simulates a "scroll" (animation) to the CGPoint I want, but while it's scrolling if the user wants to manually put their finger on it and start scrolling or just stop it, the user can't over-ride this animation until after it's completed.
Anyone have any ideas of a better method to animate it with over-ride capabilities, and when to call said over-ride capabilities (I'm assuming this will involve touchesBegan on scrollView's view)

Simply add UIViewAnimationOptionAllowUserInteraction to your animation options:
[UIView animateWithDuration:1.25f delay:0.0f options:(UIViewAnimationOptionAllowUserInteraction) animations:^{
_scrollView.contentOffset = CGPointMake(0, 800);
}
completion:nil];
And cancel the animation on the UIScrollView scrollViewWillBeginDragging: delegate method
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//Storing current offset
CALayer *currentLayer = _scrollView.layer.presentationLayer;
CGPoint scrollBoundsOrigin = currentLayer.bounds.origin;
//Cancelling animations
[_scrollView.layer removeAllAnimations];
//Restore offset
_scrollView.contentOffset = scrollBoundsOrigin;
}

Related

how to add bounce animation to animateWithDuration?

I have a simple animation that im performing in my scroll view delegate method scrollViewDidEndDragging.
It looks like this:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(#"finger was lifted");
[UIView animateWithDuration:1.0
animations:^{
self.homeLabel.frame = self.view.frame;
}];
}
Using this animation after lifting the finger the my homeLabel is coming from top, and i want to add it a bounce animation to the label, so when it comes from top, instead of landing smoothly it will have a nice bounce...how can i DO THAT? thanksss
You can use the usingSpringWithDamping animation function.
[UIView animateWithDuration:1.0 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:5.0 options:UIViewAnimationOptionCurveLinear animations:^{
self.homeLabel.frame = self.view.frame;
} completion:^(BOOL finished) {
}];
Adjusting the Spring Damping and Initial Spring Velocity can give you the effect you want.
One good solution is to create a custom layer for your view that overrides the addAnimation:forKey: method to include a custom timing function.
This answer goes into the specifics of how to do that.
Another option is to take a look at key frame animation. This question and answer covers that approach very well.

UIView animateWithDuration not getting executed

I am trying to move a UIView from the bottom to the top.
I am using iOS SDK 7.0, the uiviewcontroller's autolayout is on.
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.view bringSubviewToFront: myView];
[self moveFromBottom];
}
- (void) moveFromBottom{
[myView setBackgroundColor:[UIColor redColor]];
CGPoint top = myView.center;
top.y = self.view.frame.size.height - top.y;
[UIView animateWithDuration:5.0f
delay:0.0f
options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionBeginFromCurrentState
animations:^{
myView.center = top;
}
completion:^(BOOL finished){
if (finished) {
NSLog(#"finished");
}
}
];
The completion block gets executed and print finish but the UIView is not moved.
I also tried animate frame instead of center, which does not work neither.
But if I try to animate alpha instead it will work
edit: if I turn off autolayout in the storyboard it will also work.
You cannot explicitly set the frame or center when Autolayout is turned on. My suggestion would be to create an IBOutlet for the y-origin constraint on myView and set the constant property of that in your animation block. That should animate properly.
Where is myView initially? If it is dead center:
top.y = self.view.frame.size.height - top.y;
will be equal to the initial value of top.y. so it will not move. Did you mean to move it flush to the top. If so I think it should be:
top.y = (myView.frame.size.height/2.0f);
Also if you have auto layout enabled, check what constraints you have and make sure its not forcing it to pin in its position. I would disable auto layout to make sure this is not causing your issue. If all else fails, NSLog the value of top.y to make sure its what you intended.

Simulate UIScrollView Deceleration

I have an UIPanGestureRecognize which I use to change the frame of a view. Is there a way to simulate the deceleration of the UIScrollView or UITableView when the gesture's state is UIGestureRecognizerStateEnded? Here is my current code:
if (panGesture.state == UIGestureRecognizerStateEnded)
{
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.view.frame = CGRectMake(182, 0, self.view.frame.size.width, self.view.frame.size.height);
}
completion:^(BOOL finished) {
if (finished) {
//Do something
}
}];
}
but this is not a smooth scroll. I would like something that decelerates until it stops to the point I've set. Thanks
Session 223 at WWDC 2012, "Enhancing User Experience With Scroll Views", covered a method to use a scrollview's behavior and "feel" to animate the position of a different view (without the scrollview ever actually being visible to the user).
The benefit of the method shown in the session is that your deceleration would always match UIScrollView's, now and forever.
https://developer.apple.com/videos/wwdc/2012/?id=223
You would have to come up with an algorithm of some sort to calculate where you want the view to stop at depending on the velocity of the gesture, which can be obtained like this:
CGPoint velocity = [panGesture velocityInView:panGesture.view];
From there it should just be a matter of animating your view into its calculated resting place and adding an animation to get it there. I believe UIViewAnimationOptionCurveEaseOut would be appropriate here.

iOS UIScrollView animation after animation

I want something similar in purpose to Flipboard slight flipping animation on app start. Flipboard when launched has this slight flipping of up and down to show users unfamiliar with the interface that it is flippable.
I have a UIScrollView I want to animate a bit to show the user that it's scrollable. So I want to scroll to the right a little bit and back. UIScrollView has a setContentOffset:animated: message without a completion clause. I find that calling it twice results in seemingly no animation. What if I want an animation after animation in succession?
EDIT:
Thanks Levi for the answer.
And for the record, there is UIViewAnimationOptionAutoreverse and UIViewAnimationOptionRepeat that I can use. So this is what I ended up with that works.
CGPoint offset = self.scrollView.contentOffset;
CGPoint newOffset = CGPointMake(offset.x+100, offset.y);
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAutoreverse |UIViewAnimationOptionRepeat animations:^{
[UIView setAnimationRepeatCount: 2];
[self.scrollView setContentOffset:newOffset animated: NO];
} completion:^(BOOL finished) {
[self.scrollView setContentOffset:offset animated:NO];
}];
For a scrollView, tableView or collectionView if you do something like this:
[self.collectionView setContentOffset:CGPointMake(self.collectionView.contentOffset.x+260.0,
self.collectionView.contentOffset.y)
animated:YES];
then you'll get back a:
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
when the scroll finishes.
You do NOT get this callback if the user moves the view.
Two options:
1) Use the -(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView delegate callback
2) Try to put it into an animation block (with ... animated:NO];), which has the completion part.

How to resize a view mid-way during a moving animation?

During a sliding animation(down, pause, then up back to the original position) of a subview, the device is rotated, so the superview is rotated. I want to keep the subview's width the same as the superview, so I need to resize it during its sliding animation.
Here is the sliding animation code:
[UIView animateWithDuration:0.3 animations:^{
self.frame = finalFrame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 delay:3 options:0 animations:^{
self.frame = initFrame;
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}];
This is the method that is called when I detect rotation:
- (void)rotate:(NSNotification *)notif {
// What to do here to adjust the width but also keep the sliding animation going.
}
It seems there is no auto-resizing magic that can be used here. One must:
Record the progress of the animations.
On detection of rotations, cancel the old animations, adjust the view size, and add new animations starting from the current progress.
Here is a sample project for reference: http://d.pr/f/M4UW.
You can animate the bounds of the layer to change the width. Just make the height the same and apply an animation for the bounds.
If you want both animations to have the same duration, timing function etc. then you could add them both to an animation group and add that group to the layer you are animating.

Resources