I am trying to reproduce the behaviour of the slide up menu of the new iOS Google Maps application.
So basically it's a view that you can slide up with panning up to a certain point or slide down to a certain point. This view can also with sliding to the right and to the left like a paginated scroll view.
It should either scroll up and down or slide to the side but not both at the same time.
After a lot of research and testing I have something that's close but not quite working like need it to.
My implementation is a UIScrollView with a frame of 320x400 and content view of 960x400 with paginated scrolling. Then I add a UIPanGestureRecognizer that handles the slide up of the whole view.
Here is the handleTouch IBAction of the PanRecognizer :
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender {
NSLog(@"Panning");
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
_firstX = [[sender view] center].x;
_firstY = [[sender view] center].y;
}
if (!IS_IPHONE_5) {
if (_firstY < 216)
translatedPoint = CGPointMake(_firstX, 216);
else
translatedPoint = CGPointMake(_firstX, _firstY+translatedPoint.y);
}
else {
if (_firstY < 307)
translatedPoint = CGPointMake(_firstX, 307);
else
translatedPoint = CGPointMake(_firstX, _firstY+translatedPoint.y);
}
[[sender view] setCenter:translatedPoint];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
CGFloat velocityY = (0.2*[(UIPanGestureRecognizer*)sender velocityInView:self.view].y);
CGFloat finalX = _firstX;
CGFloat finalY = translatedPoint.y + velocityY;
if(finalY < _firstY) {
if (IS_IPHONE_5)
finalY = 307;
else
finalY = 216;
}
else if(finalY > _firstY) {
if (IS_IPHONE_5)
finalY = 605;
else
finalY = 515;
}
CGFloat animationDuration = (ABS(velocityY)*.0002)+.2;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidFinish)];
[[sender view] setCenter:CGPointMake(finalX, finalY)];
[UIView commitAnimations];
}}
So basically if the pan slide the view up and not to the sides. The problem I have with this handlePan method is that I can't make it work so that it doesn't allow scrolling higher than a point. Which it what I'm trying to do with :
if (_firstY < 216)
translatedPoint = CGPointMake(_firstX, 216);
else
translatedPoint = CGPointMake(_firstX, _firstY+translatedPoint.y);
The biggest problem thought is that the UIScrollView pan gesture recognizer is handling the pan at the same time than the one I added. Which means the UIScrollView is slided up and to the sides at the same time if I slide up the view with my finger by moving it to the sides as well.
Same is happening if I try to slide to the sides only and move the view up 1 pixel while doing, my pan recognizer ends and slides the view up completely.
The workaround I found is to set my pan recognizer to require the UIScrollview pan recognizer to fail to work.
[_panGestureRecognizer requireGestureRecognizerToFail: _slideUpScrollView.panGestureRecognizer];
So now when I slide to the sides it works and doesn't move the view up. The problem thought is that it sets itself as failed only when you remove your finger and the view didn't scroll to the sides. What happens is that you can't pan the view up anymore but if you flick up inside it does the goes the "UIGestureRecognizerStateEnded" if and slides the view up.
I looked at UIPanGestureRecognizer topics and looked at few options including, subclassing my pan recognizer to make it recognise only slide up pans and not those of the side.
Do you guys I think I am using the right strategy or should I look at it another way?
The ideal solution would be that when a slide to the side is recorded, it only moves content horizontally and is handle by the UIScrollView and that when an horizontal pan is recorded, it only pans vertically and is handled by my panreconizer. The same behaviour that Safari has with horizontal and vertical scrolling. Though I didn't figure out how to implement that.
Thanks for reading, let me know what you think. It would be great if many apps had a great slide up menu like Google Maps!
Edit : I'm targeting iOS 6.
OK, I figured it out!
I used examples from UIPanGestureRecognizer - Only vertical or horizontal to limit my pan to up and down to vertical scrolling and made turn it to state failed when panned horizontally.
I also used : Restricting UIPanGestureRecognizer movement to block the view from panning to far up or down.
Finally I reversed the requiresToFail to :
[_slideUpScrollView.panGestureRecognizer requireGestureRecognizerToFail:_panGestureRecognizer];
And there it works!
Let me know if you have questions or have improvements to propose!
Thanks!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With