objective-c - 什么可以阻止在动画期间遵守自动布局约束?

标签 objective-c animation autolayout constraints tvos

我正在尝试将 View 捕捉到 UITabBarController 的 tabBar (UITabBar) 以永不隐藏它(Apple 在 tvOS App Store 的“精选”选项卡中执行此操作的方式)。

我可以通过在直接包含在 UITabBarController 中的 UIViewController 中设置约束来使其工作。当标签栏被隐藏并显示时, View (在我的情况下,uicollectionview)完美地遵循动画。但是当我的 UIViewController 位于 UINavigationController 中时,它就无法正常工作。它最终会更新,但是当 UITabBar 正在动画(隐藏和显示)时,它不会更新。

以下是我如何使用 NSLayoutConstraints 设置约束: UIView *targetView = self.collectionView;

NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:targetView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.tabBarController.tabBar attribute:NSLayoutAttributeBottom multiplier:1 constant:0];  
NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:targetView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:0];  
NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:targetView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1 constant:0];  
NSLayoutConstraint *constraint4 = [NSLayoutConstraint constraintWithItem:targetView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];  

[self.view.window addConstraint:constraint1];  
[self.view addConstraints:@[constraint2, constraint3, constraint4]];  

下面是我如何使用 Masonry 设置相同的约束(两者具有相同的结果,但这更具可读性):

[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.width.height.equalTo(self.view);
        make.top.equalTo(self.tabBarController.tabBar.mas_bottom);
    }]; 

这是一个演示我的问题的示例项目: https://www.dropbox.com/s/bxbi0gyidxhu2bz/SampleMovingWithTabBar.zip?dl=1

这是错误还是预期行为?

我试图在另一个更复杂的应用程序中实现这种“ View 不隐藏在选项卡栏下”的行为,但我得到了同样的奇怪行为。尽管在这种情况下不涉及 UINavigationController。 View 直接位于 UIViewController 中(它是 UITabBarController 的 viewControllers 数组的一部分)。

什么可以阻止在动画期间遵守自动布局约束?

这是我链接到的演示项目中的 View Controller 层次结构的样子(UINavigationController 中的 View Controller 是显示/隐藏选项卡栏时不设置动画的 View Controller ):

<UITabBarController 0x7fca42d10bb0>, state: appeared, view: <UILayoutContainerView 0x7fca42f848b0>
   | <FirstViewController 0x7fca42d11340>, state: disappeared, view: <UIView 0x7fca42f96510>
   | <UINavigationController 0x7fca43812000>, state: appeared, view: <UILayoutContainerView 0x7fca42d46200>
   |    | <FirstViewController 0x7fca42f347f0>, state: appeared, view: <UIView 0x7fca42f8bd90>

最佳答案

每当您使用 CoreAnimation API 进行动画时,布局约束不会在 transient 动画期间遵守约束。

当您使用 NSLayoutconstraint 的属性 时,例如 constant 用于动画,那么自动布局会在 transient 动画期间遵守约束。

CoreAnimations API 包括 UIView 的基于 block 的动画。如果您有兴趣进一步阅读,那么这里是 wwdc video

但是,查看您的代码,我认为这不是您的问题。您希望在 UITabbar 设置动画时遵守布局约束。您只需要在 viewDidLayoutSubviews 而不是 videDidAppear 中设置您的约束,并且您应该使用现有代码进行所有设置。

编辑---

我得到了有关该问题的一些其他详细信息。所以首先这不是苹果的错误。 UITabBar 只负责它的直接 subview Controller 。它没有关于它的子结构的任何信息。您有责任链接该责任。

解决此问题的方法是监听 UIViewController 的转换调用并相应地设置动画。

这是神奇的代码。将此添加到您的 View Controller 。

-(void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator{

    NSString *prevFocusViewClassName = NSStringFromClass([context.previouslyFocusedView class]);
    NSString *nextFocusedView = NSStringFromClass([context.nextFocusedView class]);

    // The tabbar is going to disappear
    if ([prevFocusViewClassName isEqualToString:kUITabBarButtonClassName] &&
        ![nextFocusedView isEqualToString:kUITabBarButtonClassName]) {
        [self.view layoutIfNeeded];

        [coordinator addCoordinatedAnimations:^{
            [self.view layoutIfNeeded];
        } completion:nil];
        // The tabbar is going to appear
    } else if (![prevFocusViewClassName isEqualToString:kUITabBarButtonClassName] &&
               [nextFocusedView isEqualToString:kUITabBarButtonClassName]) {
        [self.view layoutIfNeeded];

        [coordinator addCoordinatedAnimations:^{
            [self.view layoutIfNeeded];
        } completion:nil];
    }

}

我已经用预期的输出修复了你的代码 https://www.dropbox.com/s/c8jdw367a3bnb42/SampleMovingWithTabBar-2.zip?dl=0

关于objective-c - 什么可以阻止在动画期间遵守自动布局约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36297333/

相关文章:

iphone - UITableView 给出空表,不加载数据

iphone - 将 UIImage 设置为 UIBarButton 项目

javascript - Raphael JS 路径的“删除”动画

animation - 如何在 LOVE 2D 中创建行走动画

ios - 以编程方式将 AutoLayout 用于搜索栏和 UITableView

ios - 自动布局降低某些 View 的高度

objective-c - NSTextField 两次捕获返回键事件

objective-c - Objective-C 中的类别用法

javascript - 在 JavaScript 游戏中使用 setInterval 代替 requestAnimationFrame

ios - AutoLayout:UIImageView 和 Aspect Fit 内容模式