我想实现与 Google map (iOS) 非常接近的东西,但我有一些疑问。
但首先,更好的解释和需要考虑的事项:
------------ 答案------------
感谢 Jugale 的贡献,这里有一个存储库,每个人都可以下载并测试所有内容。
https://github.com/vCrespoP/VCSlidingView
------------ 原始问题------------
- 您点击 map 内的一个点,一个 View 从底部进入,但是当您与该摘要 View 交互时:
- 请注意,只需拉动一点,导航栏就已经设置好。
- 滚动到顶部后,您可以继续滚动,内部 ScrollView 将继续滚动。
- 当您“反转”关闭 View 的操作时,PanGesture 不会与内部 scrollView 混淆(另一种方式相同,scrollView VS 关闭)
这是实际操作:
疑问:
- 我尝试将其作为交互式过渡 (UIPercentDrivenInteractiveTransition) 并在 2 个 Controller 中将 Map 与 Details 分开,但我遇到了 UIPanGesture 干扰 scrollView 的问题。
- 也许最好将它作为一个 subview 来处理那里的所有事情?或多或少像 MBPullDownController(虽然它在 iOS8 上有一些问题)-> https://github.com/matej/MBPullDownController
那么,有人知道任何框架,已经使用过,或者知道如何以好的方式做到这一点吗?
谢谢你的时间:D
最佳答案
通过我的实现来看,以下内容似乎是正确的:
- 我有一个
UIViewController
的子类,它是 View Controller - 我有一个
UIView
的子类,它是覆盖层(此后称为“覆盖层”)(实际上对我来说这是一个UIScrollView
因为它需要也横向移动,但我会尝试过滤掉不必要的代码) - 我有另一个加载覆盖内容的
UIView
子类(“内容包装器”) - 内容包装器有一个
UIScrollView
属性,其中加载了所有其他 View (“内容 View ”)
View Controller 负责初始化叠加层,设置它的初始框架(高度是屏幕的高度)并将内容传递给它,仅此而已。
通过它的 -initWithFrame
方法,叠加层使用 UIDynamicItemBehavior
自行设置。它还创建了一些 UICollisionBehavior
对象:一个在屏幕顶部,一个在屏幕底部下方,正好位于正确的 y 位置,以便叠加层的顶部部分可见(如GIF 的第一帧)。还设置了一个 UIGravityBehavior
以保持叠加层位于较低的碰撞边界上。当然,_animator = [[UIDynamicAnimator alloc...
也设置好了。
最后:
_pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan)];
_pan.delegate = self;
_pan.cancelsTouchesInView = FALSE;
overlay 类还有一些其他有用的方法,例如改变重力的方向,这样 overlay 就可以捕捉到屏幕的顶部或底部。
_pan
处理程序使用 UISnapBehavior
使叠加层在用户手指下方的屏幕上动态地上下移动:
- (void)handlePan
{
[self handlePanFromPanGestureRecogniser:_pan];
}
- (void)handlePanFromPanGestureRecogniser:(UIPanGestureRecognizer *)pan
{
CGFloat d = [pan velocityInView:self.superview.superview].y;
CGRect r = self.frame;
r.origin.y = r.origin.y + (d*0.057);
if (r.origin.y < 20)
{
r.origin.y = 20;
}
else if (r.origin.y > [UIScreen mainScreen].bounds.size.height - PEEKING_HEIGHT)
{
r.origin.y = [UIScreen mainScreen].bounds.size.height - PEEKING_HEIGHT;
}
if (pan.state == UIGestureRecognizerStateEnded)
{
[self panGestureEnded];
}
else if (pan.state == UIGestureRecognizerStateBegan)
{
[self snapToBottom];
[self removeGestureRecognizer:_tap];
}
else
{
[_animator removeBehavior:_findersnap];
_findersnap = [[UISnapBehavior alloc] initWithItem:self snapToPoint:CGPointMake(CGRectGetMidX(r), CGRectGetMidY(r))];
[_animator addBehavior:_findersnap];
}
}
- (void)panGestureEnded
{
[_animator removeBehavior:_findersnap];
CGPoint vel = [_dynamicSelf linearVelocityForItem:self];
if (fabsf(vel.y) > 250.0)
{
if (vel.y < 0)
{
[self snapToTop];
}
else
{
[self snapToBottom];
}
}
else
{
if (self.frame.origin.y > (self.superview.bounds.size.height/2))
{
[self snapToBottom];
}
else
{
[self snapToTop];
}
}
}
内容包装器监听内容 View 产生的滚动事件:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//this is our fancy way of getting the pan to work when the scrollview is in the way
if (scrollView.contentOffset.y <= 0 && _dragging)
{
_shouldForwardScrollEvents = TRUE;
}
if (_shouldForwardScrollEvents)
{
if ([_delegate respondsToSelector:@selector(theContentWrapper:isForwardingGestureRecogniserTouches:)])
{
[_delegate theContentWrapper:self isForwardingGestureRecogniserTouches:scrollView.panGestureRecognizer];
}
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
_dragging = FALSE;//scrollviewdidscroll must not be called after this
if (scrollView.contentOffset.y <= 0 || _shouldForwardScrollEvents)
{
if ([_delegate respondsToSelector:@selector(theContentWrapperStoppedBeingDragged:)])
{
[_delegate theContentWrapperStoppedBeingDragged:self];
}
}
_shouldForwardScrollEvents = FALSE;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
_dragging = TRUE;
}
如您所见,当 bool shouldForwardScrollEvents
为 TRUE
时,我们将 scrollView.panGestureRecognizer
发送到内容包装器的委托(delegate)(覆盖层) . overlay 像这样实现委托(delegate)方法:
- (void)theContentWrapper:(TheContentWrapper *)contentWrapper isForwardingGestureRecogniserTouches:(UIPanGestureRecognizer *)contentViewPan
{
[self handlePanFromPanGestureRecogniser:contentViewPan];
}
- (void)theContentWrapperStoppedBeingDragged:(TheContentWrapper *)contentWrapper
{
//because the scrollview internal pan doesn't tell use when it's state == ENDED
[self panGestureEnded];
}
希望其中至少有一部分对某人有用!
关于ios - 交互式过渡,如谷歌地图 (iOS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26604395/