【问题标题】:How to force a view animation to finish before executing sendSubviewToBack?如何在执行 sendSubviewToBack 之前强制视图动画完成?
【发布时间】:2015-01-15 14:17:23
【问题描述】:

我正在构建一个页面浏览器,它将页面动画化为“纸张”被拉到一堆纸上。为了保持流畅的动画,我使用了 3 个相互堆叠的 UIView。这三个视图包含当前页面(顶部)、上一页(中间)和下一页(底部)。

在下面的代码中,我想将顶视图拖到右侧,露出下面的上一页。这工作正常。但是,在那之后,我需要将顶部页面移动到堆栈的底部,以便为用户下次翻页时准备三个视图的堆栈。我为此使用了 sendSubviewToBack 方法。

我的问题是 ViewSample[Top] 在动画开始后立即发送到堆栈底部。如何强制动画在被发送到堆栈底部之前完成(以便 ViewSample[Top] 完全移出屏幕)?

ViewSample[Top].center = CGPointMake(x,y);

[UIView animateWithDuration:0.5
        animations:^
{ 
   ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right 
}
completion:^(BOOL finished)
{ 
}
];

[self.MainView sendSubviewToBack:ViewSample[Top]];

编辑

我刚刚遇到了一个非常奇怪的行为,这与我的问题有关。 我听从了您的建议,发现动画“已完成”部分的行为取决于 AFTERWARDS 后设置的变量“top”的值:

ViewSample[Top].center = CGPointMake(x,y);

[UIView animateWithDuration:0.5
        animations:^
{ 
   ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right 
}
completion:^(BOOL finished)
{ [self.MainView sendSubviewToBack:ViewSample[Top]];
}
];

Top++; // THIS COMMAND AFFECTS THE LINE ABOVE!!!

换句话说,当我添加“Top++;”行时即使语句 sendSubviewToBack 先出现,另一个 View 也会移回堆栈上。这让我很困惑。这有意义吗?是bug吗?

【问题讨论】:

    标签: ios animation uiview


    【解决方案1】:

    其他答案正确识别了问题。您在更新代码时遇到的问题是执行顺序问题:

    因为补全是在动画完成后才执行的,所以你的代码实际上是按照这个顺序执行的:

    1. ViewSample[Top].center = CGPointMake(x,y);
    2. ViewSample[Top].center = CGPointMake(x+w,y);
    3. Top++;
    4. [self.MainView sendSubviewToBack:ViewSample[Top]];

    有两种可能的解决方案。您可以将视图存储在变量中,以便在所有调用中拥有相同的视图,也可以延迟设置 Top 的值直到完成。

    选项 1

    UIView *viewMovingFromTopToBottom = ViewSample[Top];
    
    viewMovingFromTopToBottom.center = CGPointMake(x,y);
    
    [UIView animateWithDuration:0.5 animations:^{ 
        viewMovingFromTopToBottom.center = CGPointMake(x+w,y); //slide away to the right 
    } completion:^(BOOL finished) {
        [self.MainView sendSubviewToBack:viewMovingFromTopToBottom];
    }];
    
    Top++;
    // Other code that depends on the new value of Top...
    

    选项 2

    ViewSample[Top].center = CGPointMake(x,y);
    
    [UIView animateWithDuration:0.5 animations:^{ 
        ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right 
    } completion:^(BOOL finished) {
        [self.MainView sendSubviewToBack:ViewSample[Top]];
        Top++;
        // Other code that depends on the new value of Top...
    }];
    

    哪个选项对您最有意义取决于您在做什么。如果您将动画链接在一起,您可能希望将大部分代码移动到完成块中以延迟它直到幻灯片动画完成。如果您有很多工作需要立即完成而不依赖于动画,您可能需要使用选项 1 来配置动画并继续。或者您可能想要混合使用。

    【讨论】:

    • 我已经选择了您的选项 1。但是,以下代码: UIView *viewMovingFromTopToBottom = ViewSample[Top]; ……没有效果。视图仍然是空的。有什么想法吗?
    • 您是否有将视图动画返回正确位置的代码?
    【解决方案2】:

    使用completion 块:

     ViewSample[Top].center = CGPointMake(x,y);
    
    [UIView animateWithDuration:0.5
            animations:^
    { 
      ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right 
    }
    completion:^(BOOL finished)
    {
      [self.MainView sendSubviewToBack:ViewSample[Top]];
    }
    ];
    

    【讨论】:

    • 见上文。不幸的是,这没有任何效果。
    【解决方案3】:

    Brian Nickel 的第一个建议(局部变量)成功了。但是,有一个警告:您必须注意语句的顺序。这不起作用: [self.MainView addSubview:LocalView]; 本地视图=视图[1]; ...而这样做: 本地视图=视图[1]; [self.MainView addSubview:LocalView]; 我第一次有顶级版本,它只是让空白视​​图出现。

    因此,一种可行的方法是使用三个全局视图进行页面缓存,并使用两个本地视图进行动画。局部视图以适当的顺序堆叠,从全局视图复制数据,然后执行动画。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多