How to make a dragging UIView decelerating? - iphone

I have a UIView that can be dragged with the finger which I've implemented by using a UIPanGestureRecognizer. This allows me to drag a view horizontally ; left or right.
I make my view moving while receiving the following state from the UIPanGestureRecognizer (using the translationInView: method):
UIGestureRecognizerStateBegan
UIGestureRecognizerStateChanged
What happens for now, is the view stops moving as soon as the finger leaves the surface of the screen, which renders a non natural effect.
What I would like, would be that the dragging view decelerates starting from the state UIGestureRecognizerStateEnded by stopping smoothly.
Such a behavior is used by UIScrollView class and subclasses (UIWebView, UITableView, etc.).
I've tried severals approaches by calculating from the velocity, the time the touch occurred and stopped a stop distance, etc. But honestly I have a feeling of going nowhere to get a natural behavior. I even tried to use physics engine like Chipmunk. But I find this to complicated for what I try to achieve, and I'm pretty sure there should be a better (if not easier) solution.
Thanks a lot!
Jérémy

In your gesture recognizer, make it so that when your finger leaves the screen, you begin an animation to continue to scroll a bit, for a short duration, with an "Ease Out" transition.
Maybe something like:
[UIView beginAnimations:#"FingerOff" context:nil];
[UIView setAnimationDuration:0.25f];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIAnimationViewEaseOut];
[myView setFrame:newFrame];
[UIView commitAnimation];
You can substitute setFrame to something else - whatever establishes how you want to scroll or view - maybe even a setCenter. Make it a scroll a bit "further" than the current position.

Related

Core Animation and UIImageView returning to starting position

I have a UIImageView that I'm moving across the screen based on a user swiping. I accomplish this using Core Animation:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
movingView.frame = theRect;
[UIView commitAnimations];
It always starts out fine, but partway through going from its original location to the "theRect" location, it stops and the UIImageView jumps back to its starting point. It's never at the same point. Sometimes gets almost all the way through before jumping back, sometimes only barely moving then jumping back. No other code is running after this. I've tried changing the duration and it doesn't seem to matter.
If I add in:
[UIView setAnimationDidStopSelector:#selector(completeAnimation:finished:context:)];
[UIView setAnimationDelegate:self];
Then it actually delays until the Duration is complete and runs the selector, even if the image itself stops and returns to its starting point almost immediately.
Hopefully someone can give me some hints at what might be going on here.
If using autolayout, you can animate the changing of the constraint, not animating the change of the frame (because when constraints are reapplied, the original location will be restored). See Animating an image view to slide upwards for an example.

Effect like deletion in ios

I need hint/code like deletion/move app effect on iOS, normally i have started the code, I am using UIButton list in UIScroll.
So my question is that supposes I have 8 to 10 button in screen and i want to change their position with dragging. for example choose 6th button and move or set to between 1 and 2. when I put them in to between the position of other button will change.
I am using UIPanGestureRecognizer for dragging.
download, Tiles-v1.0.zip, and check code, this is what i used when i needed to implement that.
reference: Move UIViews to avoid collision like rearranging icons on Springboard
If you already have the code for dragging, the rest is easy. Just use UIView Animation.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
...
[button setFrame:newFrame];
...
[UIView commitAnimations];
Basically, just move your buttons to the their new positions in that beginAnimations - commitAnimations block.
Hope this helps.

How do i make a UIScrollView scroll automatically at a certain speed?

I am using touchesBegan and touchesMoved to track a user's interaction, so I can see where the user has touched the screen. What I want to do is when they take their finger to the last 20 pixels of the screen, have the UIScrollView scroll1 to scroll down. But how do i define a speed? Surely a while statement would do it far too rapidly, and a UIView animation would move it to a certain place but only the once.
You can do this by the following code :
[UIScrollView beginAnimations:#"scrollAnimation" context:nil];
[UIScrollView setAnimationDuration:REQUIRED_ANIMATION_DURATION];
[scroll setContentOffset:CGPointMake(REQUIRED_DISTANCE_X, REQUIRED_DISTANCE_Y)];
[UIScrollView commitAnimations];
Just set the values of REQUIRED_ANIMATION_DURATION to whatever time interval you want. A smaller time interval will mean faster speed.

emulate bounce effect in iphone app without UIScrollView

I am using a pan gesture to drag an item in my app. I know I could use a UIScrollView to get that "bounce" effect when dragging to an edge. However, that seems like a hack, so I'd like to find a way to get that effect when manually dragging an item (setting its frame or center point). I'm curious if there's a standard way, or a physics library in the Accelerate framework, something like that which wouldn't require me implementing my own physics engine.
The standard UIView animation curve is one that uses the accelerate / decelerate curve, which should gives a nice "bounce back" action.
It's really easy to use. Once you decide you want to "snap back" to a location, do this:
[UIView beginAnimations:nil context:nil];
CGRect newFrame = viewToAnimate.frame;
newFrame.origin.x = snapBackXcoordinate;
viewToAnimate.frame = newFrame;
[UIView commitAnimations];
to entirely emulate the UIScrollView you'll also need to set a "maximum stretch" distance before you stop stretching more.
But why re-invent the wheel? The UIKit components you're given are there to use. If putting your view into a UIScrollView does the trick, go ahead and use it. Saves you develop and debug time.

I want to animate, in fact fade, "within" drawRect

Is there a way to make drawRect animate FROM THE PREVIOUS SCENE to the next one?
(Amazingly) you can animate inside drawRect - try it. You can fade, translate or animate any other property.
However, it starts "from fresh", from blank. So for example if you put a fade-in animation block in drawRect, the previous scene with disappear and the new scene will fade up from white.
I want the screen to fade from the previous image (drawn in the previous cycle of drawRect) to the new image I have just drawn ... err, am drawing.
Is there a way to do that, perhaps trickily by manipulating what's going on with drawRect?
This would seem to be a very common use case - blending from one scene to the next.
Does anyone know the secret?
Of course, obviously this can be done in the core animation milieu or in many other ways, but having drawRect fade from one drawRect to the next is an obvious idea. Cheers.
Astounding update thanks to the genius of WrightCS.....
Thanks only to WrightCS, we now know that drawRect handles animations perfectly. Simply paste this code at the end of any drawRect and try it:
self.alpha = 0.0;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2];
self.alpha = 1.0;
[UIView commitAnimations];
it treats the entire drawRect, no matter how complex, as one enormous block and it wraps it in that animation. Yes, it even includes painted in offscreen areas, bitmap rendering or anything else. Everything gets animated. Who knew?
The problem at hand - how to make it start the animation from the previous scene rather than start from blank?
Drawrect Is invisible. It happens in the 'backbuffer' which the iOS displays on screen only when you're ready with drawRect. So you can definitely not animate while in drawrect. However, you can commit animation instrucions from just about anywhere, including drawrect. But the animation will be performed afterwards.
Animation requires timing and showing different frames to the user.
You CAN do that all by yourself (constantly forcing a redraw and doing something slightly different in drawrect each the time) but that's a lot of work, especialy if you want it done right.
Luckily iOS has many animation effects programmed for you. Either using Core Animation, or the (more simple and basic) animation in UIKit. But since it works by animating certain properties of views (eg the alpha of a whole view, or the rotation of a whole view, ...) you might need to rearrange your views and subviews to make good use of it.
E.g. Each horse limb is separate subview and you animate their transformations (no redraw needed, iOS will do the rest)
E.g. The old and new frame are two separate views and you animate the new frame (which is on top) from alpha 0 to alpha 1.
You can animate the alpha:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2.0];
myObject.alpha = 0.0;
[UIView commitAnimations];
if you are under iOS 5.0+, you can use the following:
...
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
//do your stuff here
}completion:^(BOOL finished) {
//completition stuff go here
}];
...
The best thing you can do is to use two UIView instances and animate between them.
When you are starting the animation you have to know which is the original and final state of the animation. That's difficult if it's only one view.