Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/107.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在视图之间实现滑动/滑动动画?_Ios_Swipe - Fatal编程技术网

Ios 如何在视图之间实现滑动/滑动动画?

Ios 如何在视图之间实现滑动/滑动动画?,ios,swipe,Ios,Swipe,我有几个视图,我想在iOS程序中在它们之间滑动。现在,我使用模态样式在它们之间滑动,带有交叉溶解动画。但是,我想要一个滑动/滑动动画,就像你在主屏幕上看到的那样。我不知道如何编写这样的转换代码,而且动画样式不是可用的模式转换样式。谁能给我一个代码的例子吗?它不需要是模态模型或任何东西,我只是发现这很容易 您可以创建cattransition动画。下面是一个示例,说明如何将第二个视图(从左)滑入屏幕,同时将当前视图推出: UIView *theParentView = [self.view sup

我有几个视图,我想在iOS程序中在它们之间滑动。现在,我使用模态样式在它们之间滑动,带有交叉溶解动画。但是,我想要一个滑动/滑动动画,就像你在主屏幕上看到的那样。我不知道如何编写这样的转换代码,而且动画样式不是可用的模式转换样式。谁能给我一个代码的例子吗?它不需要是模态模型或任何东西,我只是发现这很容易

您可以创建
cattransition
动画。下面是一个示例,说明如何将第二个视图(从左)滑入屏幕,同时将当前视图推出:

UIView *theParentView = [self.view superview];

CATransition *animation = [CATransition animation];
[animation setDuration:0.3];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];

[theParentView addSubview:yourSecondViewController.view];
[self.view removeFromSuperview];

[[theParentView layer] addAnimation:animation forKey:@"showSecondViewController"];

从iOS 7开始,如果您希望为两个视图控制器之间的过渡设置动画,则应使用自定义过渡,如WWDC 2013视频中所述。例如,要自定义新视图控制器的表示形式,您可以:

  • 目标视图控制器将为演示动画指定
    self.modalPresentationStyle
    TransitionDelegate

    - (instancetype)initWithCoder:(NSCoder *)coder {
        self = [super initWithCoder:coder];
        if (self) {
            self.modalPresentationStyle = UIModalPresentationCustom;
            self.transitioningDelegate = self;
        }
        return self;
    }
    
    @interface PresentAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    @implementation PresentAnimator
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
        return 0.5;
    }
    
    // do whatever animation you want below
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
        UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    
        [[transitionContext containerView] addSubview:toViewController.view];
        CGFloat width = fromViewController.view.frame.size.width;
        CGRect originalFrame = fromViewController.view.frame;
        CGRect rightFrame = originalFrame; rightFrame.origin.x += width;
        CGRect leftFrame  = originalFrame; leftFrame.origin.x  -= width / 2.0;
        toViewController.view.frame = rightFrame;
    
        toViewController.view.layer.shadowColor = [[UIColor blackColor] CGColor];
        toViewController.view.layer.shadowRadius = 10.0;
        toViewController.view.layer.shadowOpacity = 0.5;
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            fromViewController.view.frame = leftFrame;
            toViewController.view.frame = originalFrame;
            toViewController.view.layer.shadowOpacity = 0.5;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
    }
    
    @end
    
  • 此委托(在本例中,视图控制器本身)将符合
    UIViewControllerTransitioningDelegate
    ,并实现:

    - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
                                                                       presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
        return [[PresentAnimator alloc] init];
    }
    
    // in iOS 8 and later, you'd also specify a presentation controller
    
    - (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source {
        return [[PresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
    }
    
  • 或者,如果您希望此手势具有交互性,您还可以:

    • 创建一个交互控制器(通常是
      UIPercentDrivenInteractiveTransition

    • 让您的
      UIViewControllerAnimatedTransitioning
      也实现
      interactionControllerForPresentation
      ,这显然会返回前面提到的交互控制器

    • 做一个手势(或你做了什么)来更新互动控制器

  • 这在前面提到的内容中都有描述

    有关自定义导航控制器推送/弹出的示例,请参见


    下面,请找到我的原始答案的副本,它早于自定义转换


    @sooper的回答是正确的,CATTransition可以产生你想要的效果

    但是,顺便说一句,如果你的背景不是白色的,
    CATransition
    kCATransitionPush
    在过渡结束时会有一种奇怪的淡入淡出,这可能会分散你的注意力(尤其是在图像之间导航时,它会产生轻微的闪烁效果)。如果你遇到这种情况,我发现这个简单的转换非常优雅:你可以准备你的“下一个视图”在屏幕右侧,然后设置当前视图在屏幕左侧移动的动画,同时设置下一个视图移动到当前视图所在位置的动画。请注意,在我的示例中,我在单个视图控制器中设置主视图内外的子视图动画,但您可能会想到:

    float width = self.view.frame.size.width;
    float height = self.view.frame.size.height;
    
    // my nextView hasn't been added to the main view yet, so set the frame to be off-screen
    
    [nextView setFrame:CGRectMake(width, 0.0, width, height)];
    
    // then add it to the main view
    
    [self.view addSubview:nextView];
    
    // now animate moving the current view off to the left while the next view is moved into place
    
    [UIView animateWithDuration:0.33f 
                          delay:0.0f 
                        options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                     animations:^{
                         [nextView setFrame:currView.frame];
                         [currView setFrame:CGRectMake(-width, 0.0, width, height)];
                     }
                     completion:^(BOOL finished){
                         // do whatever post processing you want (such as resetting what is "current" and what is "next")
                     }];
    
    很明显,你必须调整这个来设置你的控件,但这会产生一个非常简单的过渡,没有褪色或类似的东西,只是一个很好的平滑过渡

    需要注意的是:首先,无论是这个示例还是
    cattransition
    示例,都与SpringBoard主屏幕动画(如您所述)非常相似,它是连续的(即,如果您在刷卡的中途,您可以停下来并返回或其他任何方式)。这些转变一旦开始,就会发生。如果您需要实时交互,也可以这样做,但这是不同的

    更新:

    如果你想使用一个连续的手势来跟踪用户的手指,你可以使用
    UIPangestureRecognitizer
    而不是
    UIWipegestureRecognitizer
    ,我认为在这种情况下
    animateWithDuration
    CATTransition
    更好。我修改了我的
    handlePangestre
    以更改
    坐标以与用户的手势相协调,然后修改了上述代码以在用户放开时完成动画。效果很好。我认为你不能很容易地用
    cattransition
    做到这一点

    例如,可以在控制器的主视图上创建手势处理程序:

    [self.view addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]];
    
    处理程序可能如下所示:

    - (void)handlePan:(UIPanGestureRecognizer *)gesture
    {
        // transform the three views by the amount of the x translation
    
        CGPoint translate = [gesture translationInView:gesture.view];
        translate.y = 0.0; // I'm just doing horizontal scrolling
    
        prevView.frame = [self frameForPreviousViewWithTranslate:translate];
        currView.frame = [self frameForCurrentViewWithTranslate:translate];
        nextView.frame = [self frameForNextViewWithTranslate:translate];
    
        // if we're done with gesture, animate frames to new locations
    
        if (gesture.state == UIGestureRecognizerStateCancelled ||
            gesture.state == UIGestureRecognizerStateEnded ||
            gesture.state == UIGestureRecognizerStateFailed)
        {
            // figure out if we've moved (or flicked) more than 50% the way across
    
            CGPoint velocity = [gesture velocityInView:gesture.view];
            if (translate.x > 0.0 && (translate.x + velocity.x * 0.25) > (gesture.view.bounds.size.width / 2.0) && prevView)
            {
                // moving right (and/or flicked right)
    
                [UIView animateWithDuration:0.25
                                      delay:0.0
                                    options:UIViewAnimationOptionCurveEaseOut
                                 animations:^{
                                     prevView.frame = [self frameForCurrentViewWithTranslate:CGPointZero];
                                     currView.frame = [self frameForNextViewWithTranslate:CGPointZero];
                                 }
                                 completion:^(BOOL finished) {
                                     // do whatever you want upon completion to reflect that everything has slid to the right
    
                                     // this redefines "next" to be the old "current",
                                     // "current" to be the old "previous", and recycles
                                     // the old "next" to be the new "previous" (you'd presumably.
                                     // want to update the content for the new "previous" to reflect whatever should be there
    
                                     UIView *tempView = nextView;
                                     nextView = currView;
                                     currView = prevView;
                                     prevView = tempView;
                                     prevView.frame = [self frameForPreviousViewWithTranslate:CGPointZero];
                                 }];
            }
            else if (translate.x < 0.0 && (translate.x + velocity.x * 0.25) < -(gesture.view.frame.size.width / 2.0) && nextView)
            {
                // moving left (and/or flicked left)
    
                [UIView animateWithDuration:0.25
                                      delay:0.0
                                    options:UIViewAnimationOptionCurveEaseOut
                                 animations:^{
                                     nextView.frame = [self frameForCurrentViewWithTranslate:CGPointZero];
                                     currView.frame = [self frameForPreviousViewWithTranslate:CGPointZero];
                                 }
                                 completion:^(BOOL finished) {
                                     // do whatever you want upon completion to reflect that everything has slid to the left
    
                                     // this redefines "previous" to be the old "current",
                                     // "current" to be the old "next", and recycles
                                     // the old "previous" to be the new "next". (You'd presumably.
                                     // want to update the content for the new "next" to reflect whatever should be there
    
                                     UIView *tempView = prevView;
                                     prevView = currView;
                                     currView = nextView;
                                     nextView = tempView;
                                     nextView.frame = [self frameForNextViewWithTranslate:CGPointZero];
                                 }];
            }
            else
            {
                // return to original location
    
                [UIView animateWithDuration:0.25
                                      delay:0.0
                                    options:UIViewAnimationOptionCurveEaseOut
                                 animations:^{
                                     prevView.frame = [self frameForPreviousViewWithTranslate:CGPointZero];
                                     currView.frame = [self frameForCurrentViewWithTranslate:CGPointZero];
                                     nextView.frame = [self frameForNextViewWithTranslate:CGPointZero];
                                 }
                                 completion:NULL];
            }
        }
    }
    
    您的具体实现无疑会有所不同,但希望这能说明这个想法


    在说明了所有这些(补充和澄清了这个旧答案)之后,我应该指出,我不再使用这种技术。现在,我通常使用
    UIScrollView
    (打开“分页”)或(在iOS 6中)UIPageViewController。这使您不再需要编写这种手势处理程序(并享受滚动条、弹跳等额外功能)。在
    UIScrollView
    实现中,我只响应
    scrollViewDidScroll
    事件,以确保我正在惰性地加载必要的子视图

    如果您想在切换页面时获得与跳板相同的页面滚动/滑动效果,那么为什么不使用
    UIScrollView

    CGFloat width = 320;
    CGFloat height = 400;
    NSInteger pages = 3;
    
    UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,width,height)];
    scrollView.contentSize = CGSizeMake(width*pages, height);
    scrollView.pagingEnabled = YES;
    

    然后使用
    UIPageControl
    获取这些点:

    嘿@Rob,做得很好,就像我做的一样。我真的很想让UIPangestureRecognitor很好地工作。有没有可能得到一段代码,特别是动画?太多了!在特定控制器内的子视图之间的转换。@StudyCat当我第一次写这篇文章时,我正在手动将子视图添加到一个窗口中并移动它们,等等。随后我选择了两种更简单的解决方案,即
    UIPageViewController
    (如果需要滑动视图,请使用iOS 6.0及更高版本)或者
    UIScrollView
    (在该方法中,您打开分页,然后响应
    scrollViewWillScroll
    delegate方法,以确定哪些视图要添加为子视图。这些都是很好的方法,因为它使您摆脱了创建自己的手势识别器的过程,您可以获得滚动条或页面计数器
    - (CGRect)frameForPreviousViewWithTranslate:(CGPoint)translate
    {
        return CGRectMake(-self.view.bounds.size.width + translate.x, translate.y, self.view.bounds.size.width, self.view.bounds.size.height);
    }
    
    - (CGRect)frameForCurrentViewWithTranslate:(CGPoint)translate
    {
        return CGRectMake(translate.x, translate.y, self.view.bounds.size.width, self.view.bounds.size.height);
    }
    
    - (CGRect)frameForNextViewWithTranslate:(CGPoint)translate
    {
        return CGRectMake(self.view.bounds.size.width + translate.x, translate.y, self.view.bounds.size.width, self.view.bounds.size.height);
    }
    
    CGFloat width = 320;
    CGFloat height = 400;
    NSInteger pages = 3;
    
    UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,width,height)];
    scrollView.contentSize = CGSizeMake(width*pages, height);
    scrollView.pagingEnabled = YES;