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

我正试图将视图捕捉到UITabBarController的tabBar(UITabBar),从不隐藏它(Apple在tvOS App Store的’Featured’选项卡中的方式).

我可以通过在直接包含在UITabBarController中的UIViewController中设置约束来使其工作.当隐藏和显示标签栏时,视图(在我的例子中,是一个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

这是一个错误还是预期的行为?

我正试图在另一个更复杂的应用程序中实现这个“视图不隐藏在标签栏下”的行为,我得到了同样奇怪的行为.虽然在这种情况下没有涉及UINavigationController.该视图直接位于UIViewController(它是UITabBarController的viewControllers数组的一部分)中.

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

这是我的View Controller层次结构在我链接到的演示项目中的样子(UINavigationController中的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进行动画时,布局约束在瞬态动画期间不会受到约束.

当您使用NSLayoutconstraint的属性(如常量用于动画)时,自动布局会在瞬态动画期间遵循约束.

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

但是,看看你的代码,我认为这不是你的问题.您希望在UITabbar动画时尊重布局约束.您只需要在viewDidLayoutSubviews中设置约束而不是videDidAppear,您应该使用现有代码进行设置.

编辑—

我得到了一些关于这个问题的更多细节.首先,这不是苹果的错误. UITabBar只负责它的直接子视图控制器.它没有关于它的子结构的任何信息.你有责任将这一责任归为一类.

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

这是神奇的代码.将其添加到视图控制器.

-(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的代码

点赞