在iOS中使用手势导航UIViewControllers

在iOS中使用手势导航UIViewControllers,第1张

概述我有几个嵌入在UINavigationController中的视图控制器(一些模态,一些模型,一些推送),并使用滑动手势导航它们: // Gesture recognizersUISwipeGestureRecognizer *downGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(d 我有几个嵌入在UINavigationController中的视图控制器(一些模态,一些模型,一些推送),并使用滑动手势导航它们:

// Gesture recognizersUISwipeGestureRecognizer *downGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(dismissbutton)];downGesture.direction = UISwipeGestureRecognizerDirectionDown;[downGesture setCancelstouchesInVIEw:NO];[self.vIEw addGestureRecognizer:downGesture];

这样可以正常工作,但我希望用户能够物理地拖动模态显示的视图控制器,例如,向下和离开屏幕,而不仅仅是轻d和动画完成剩下的工作,或者在屏幕上拖动并捕捉到上一个视图而不是点击后退按钮.

我已尝试在视图上使用平移手势实现此功能,但当然前面的视图控制器在它后面是不可见的,它需要它.这种效果如何正确实现?用视图控制器控制?如果是这样,当将几个视图控制器推送到堆栈时,它会如何工作?我正在谈论的导航类型的一个例子可以在LetterPress应用程序中找到.

谢谢.

解决方法 是的,自定义容器视图是可行的方法(iOS 5及更高版本).您基本上编写自己的自定义容器,使用内置的childVIEwControllers属性来跟踪所有子视图控制器.您可能需要自己的属性(例如currentChildindex)来跟踪您当前使用的子控制器:

@property (nonatomic) NSInteger currentChildindex;

您的父控制器可能应该有一些用于非滑动相关导航的推送和d出方法,例如:

- (voID)pushChildVIEwController:(UIVIEwController *)newChildController{    // remove any other children that we've popped off,but are still lingering about    for (NSInteger index = [self.childVIEwControllers count] - 1; index > self.currentChildindex; index--)    {        UIVIEwController *childController = self.childVIEwControllers[index];        [childController willMovetoParentVIEwController:nil];        [childController.vIEw removeFromSupervIEw];        [childController removeFromParentVIEwController];    }    // get reference to the current child controller    UIVIEwController *currentChildController = self.childVIEwControllers[self.currentChildindex];    // set new child to be off to the right    CGRect frame = self.containerVIEw.bounds;    frame.origin.x += frame.size.wIDth;    newChildController.vIEw.frame = frame;    // add the new child    [self addChildVIEwController:newChildController];    [self.containerVIEw addSubvIEw:newChildController.vIEw];    [newChildController dIDMovetoParentVIEwController:self];    [UIVIEw animateWithDuration:0.5                     animations:^{                         CGRect frame = self.containerVIEw.bounds;                         newChildController.vIEw.frame = frame;                         frame.origin.x -= frame.size.wIDth;                         currentChildController.vIEw.frame = frame;                     }];    self.currentChildindex++;}- (voID)popChildVIEwController{    if (self.currentChildindex == 0)        return;    UIVIEwController *currentChildController = self.childVIEwControllers[self.currentChildindex];    self.currentChildindex--;    UIVIEwController *prevIoUsChildController = self.childVIEwControllers[self.currentChildindex];    CGRect onScreenFrame = self.containerVIEw.bounds;    CGRect offToTheRightFrame = self.containerVIEw.bounds;    offToTheRightFrame.origin.x += offToTheRightFrame.size.wIDth;    [UIVIEw animateWithDuration:0.5                     animations:^{                         currentChildController.vIEw.frame = offToTheRightFrame;                         prevIoUsChildController.vIEw.frame = onScreenFrame;                     }];}

就个人而言,我有一个为这两种方法定义的协议,并确保我的父控制器配置为符合该协议:

@protocol ParentControllerDelegate <NSObject>- (voID)pushChildVIEwController:(UIVIEwController *)newChildController;- (voID)popChildVIEwController;@end@interface ParentVIEwController : UIVIEwController <ParentControllerDelegate>...@end

然后,当一个孩子想要推一个新孩子时,它可以这样做:

ChildVIEwController *controller = ... // instantiate and configure your next controller however you want to do thatID<ParentControllerDelegate> parent = (ID)self.parentVIEwController;NSAssert([parent conformstoprotocol:@protocol(ParentControllerDelegate)],@"Parent must conform to ParentControllerDelegate");[parent pushChildVIEwController:controller];

当一个孩子想要脱身时,它可以这样做:

ID<ParentControllerDelegate> parent = (ID)self.parentVIEwController;NSAssert([parent conformstoprotocol:@protocol(ParentControllerDelegate)],@"Parent must conform to ParentControllerDelegate");[parent popChildVIEwController];

然后父视图控制器设置了平移手势,以处理用户从一个孩子到另一个孩子的平移:

- (voID)handlePan:(UIPanGestureRecognizer *)gesture{    static UIVIEw *currentVIEw;    static UIVIEw *prevIoUsVIEw;    static UIVIEw *nextVIEw;    if (gesture.state == UIGestureRecognizerStateBegan)    {        // IDentify prevIoUs vIEw (if any)        if (self.currentChildindex > 0)        {            UIVIEwController *prevIoUs = self.childVIEwControllers[self.currentChildindex - 1];            prevIoUsVIEw = prevIoUs.vIEw;        }        else        {            prevIoUsVIEw = nil;        }        // IDentify next vIEw (if any)        if (self.currentChildindex < ([self.childVIEwControllers count] - 1))        {            UIVIEwController *next = self.childVIEwControllers[self.currentChildindex + 1];            nextVIEw = next.vIEw;        }        else        {            nextVIEw = nil;        }        // IDentify current vIEw        UIVIEwController *current = self.childVIEwControllers[self.currentChildindex];        currentVIEw = current.vIEw;    }    // if we're in the mIDdle of a pan,let's adjust the center of the vIEws accordingly    CGPoint translation = [gesture translationInVIEw:gesture.vIEw.supervIEw];    prevIoUsVIEw.transform = CGAffinetransformMakeTranslation(translation.x,0.0);    currentVIEw.transform = CGAffinetransformMakeTranslation(translation.x,0.0);    nextVIEw.transform = CGAffinetransformMakeTranslation(translation.x,0.0);    // if we're all done,let's animate the completion (or if we dIDn't move far enough,// the reversal) of the pan gesture    if (gesture.state == UIGestureRecognizerStateEnded ||        gesture.state == UIGestureRecognizerStateCancelled ||        gesture.state == UIGestureRecognizerStateFailed)    {        CGPoint center = currentVIEw.center;        CGPoint currentCenter = CGPointMake(center.x + translation.x,center.y);        CGPoint offRight = CGPointMake(center.x + currentVIEw.frame.size.wIDth,center.y);        CGPoint offleft = CGPointMake(center.x - currentVIEw.frame.size.wIDth,center.y);        CGPoint veLocity = [gesture veLocityInVIEw:gesture.vIEw.supervIEw];        if ((translation.x + veLocity.x * 0.5) < (-self.containerVIEw.frame.size.wIDth / 2.0) && nextVIEw)        {            // if we finished pan to left,reset transforms            prevIoUsVIEw.transform = CGAffinetransformIDentity;            currentVIEw.transform = CGAffinetransformIDentity;            nextVIEw.transform = CGAffinetransformIDentity;            // set the starting point of the animation to pick up from where            // we had prevIoUsly transformed the vIEws            CGPoint nextCenter = CGPointMake(nextVIEw.center.x + translation.x,nextVIEw.center.y);            currentVIEw.center = currentCenter;            nextVIEw.center = nextCenter;            // and animate the moving of the vIEws to their final resting points,// adjusting the currentChildindex appropriately            [UIVIEw animateWithDuration:0.25                                  delay:0.0                                options:UIVIEwAnimationoptionCurveEaSEOut                             animations:^{                                 currentVIEw.center = offleft;                                 nextVIEw.center = center;                                 self.currentChildindex++;                             }                             completion:NulL];        }        else if ((translation.x + veLocity.x * 0.5) > (self.containerVIEw.frame.size.wIDth / 2.0) && prevIoUsVIEw)        {            // if we finished pan to right,reset transforms            prevIoUsVIEw.transform = CGAffinetransformIDentity;            currentVIEw.transform = CGAffinetransformIDentity;            nextVIEw.transform = CGAffinetransformIDentity;            // set the starting point of the animation to pick up from where            // we had prevIoUsly transformed the vIEws            CGPoint prevIoUsCenter = CGPointMake(prevIoUsVIEw.center.x + translation.x,prevIoUsVIEw.center.y);            currentVIEw.center = currentCenter;            prevIoUsVIEw.center = prevIoUsCenter;            // and animate the moving of the vIEws to their final resting points,// adjusting the currentChildindex appropriately            [UIVIEw animateWithDuration:0.25                                  delay:0.0                                options:UIVIEwAnimationoptionCurveEaSEOut                             animations:^{                                 currentVIEw.center = offRight;                                 prevIoUsVIEw.center = center;                                 self.currentChildindex--;                             }                             completion:NulL];        }        else        {            [UIVIEw animateWithDuration:0.25                                  delay:0.0                                options:UIVIEwAnimationoptionCurveEaseInOut                             animations:^{                                 prevIoUsVIEw.transform = CGAffinetransformIDentity;                                 currentVIEw.transform = CGAffinetransformIDentity;                                 nextVIEw.transform = CGAffinetransformIDentity;                             }                             completion:NulL];        }    }}

看起来你正在进行上下平移,而不是我上面使用的左右平移,但希望你得到基本的想法.

顺便说一句,在iOS 6中,您可能会使用内置容器控制器UIPageViewController更有效地完成您所询问的用户界面(使用手势在视图之间滑动).只需使用UIPageVIEwControllerTransitionStyleScroll的过渡样式和UIPageVIEwControllerNavigationorIEntationHorizo​​ntal的导航方向.不幸的是,iOS 5只允许页面卷曲转换,Apple只在iOS 6中引入了你想要的滚动转换,但如果这就是你所需要的,UIPageVIEwController比我上面列出的更有效地完成工作(你不要不必做任何自定义容器调用,不写手势识别器等.

例如,您可以将“页面视图控制器”拖到故事板上,创建UIPageVIEwController子类,然后在vIEwDIDLoad中,您需要配置第一页:

UIVIEwController *firstPage = [self.storyboard instantiateVIEwControllerWithIDentifIEr:@"1"]; // use whatever storyboard ID your left page usesself.vIEwControllerStack = [NSMutableArray arrayWithObject:firstPage];[self setVIEwControllers:@[firstPage]               direction:UIPageVIEwControllerNavigationDirectionForward                animated:NO              completion:NulL];self.dataSource = self;

然后,您需要定义以下UIPageViewControllerDataSource方法:

- (UIVIEwController *)pageVIEwController:(UIPageVIEwController *)pageVIEwController vIEwControllerAfterVIEwController:(UIVIEwController *)vIEwController{    if ([vIEwController isKindOfClass:[leftVIEwController class]])        return [self.storyboard instantiateVIEwControllerWithIDentifIEr:@"2"];    return nil;}- (UIVIEwController *)pageVIEwController:(UIPageVIEwController *)pageVIEwController vIEwControllerBeforeVIEwController:(UIVIEwController *)vIEwController{    if ([vIEwController isKindOfClass:[RightVIEwController class]])        return [self.storyboard instantiateVIEwControllerWithIDentifIEr:@"1"];    return nil;}

您的实现会有所不同(至少不同的类名和不同的故事板标识符;我还让页面视图控制器在用户请求时实例化下一页的控制器,因为我没有保留任何强引用,当我完成转换到另一个页面时会释放…你可以选择在启动时实例化这两个例程然后在例程之前和之后显然不会实例化,而是在数组中查找它们,但希望你明白了.

但关键问题是我没有任何手势代码,没有自定义容器视图控制器代码等.更简单.

总结

以上是内存溢出为你收集整理的在iOS中使用手势导航UIViewControllers全部内容,希望文章能够帮你解决在iOS中使用手势导航UIViewControllers所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1078535.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-27
下一篇 2022-05-27

发表评论

登录后才能评论

评论列表(0条)

保存