iOS   发布时间:2022-03-30  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了在iOS中使用手势导航UIViewControllers大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我有几个嵌入在UINavigationController中的视图控制器(一些模态,一些模型,一些推送),并使用滑动手势导航它们:

// Gesture recognizers
UISwipeGestureRecognizer *downGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@SELEctor(dismissButton)];
downGesture.direction = UISwipeGestureRecognizerDirectionDown;
[downGesture setCancelsTouchesInView:NO];
[self.view addGestureRecognizer:downGesture];

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

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

谢谢.

解决方法

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

@property (nonatomiC) NSInteger currentChildIndex;

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

- (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 that

id<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 uses
self.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所遇到的程序开发问题。

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

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。