在为约束设置动画时防止子视图上出现不需要的动画

Posted

技术标签:

【中文标题】在为约束设置动画时防止子视图上出现不需要的动画【英文标题】:Prevent unwanted animations on subviews when animating constraints 【发布时间】:2015-03-09 22:31:29 【问题描述】:

在为 UITableView 的高度设置动画时,通常会在 UITableViewCells 上获得不需要的动画。被重用的新单元格进来,并且在布局的子视图上有奇怪的不需要的动画。这通常在表格展开时可见。

动画通常看起来像是从角落弹出的对象,因为它出于某种原因将子视图的宽度和高度从 0 设置为它们应该的大小。

这可以通过覆盖单元格的 layoutSubviews 方法来解决。

- (void)layoutSubviews

    [UIView performWithoutAnimation:^
        [super layoutSubviews];
    ];

但这仍然不能阻止包含的子视图执行不需要的动画。当您将内容添加到单元格的 contentView 时,它也不会阻止不需要的动画。如果它也有子视图,你基本上必须覆盖你拥有的每个子视图的 layoutSubviews 方法。

这并不总是可行的,例如 contentView。我不能覆盖 contentView 类并告诉它在没有动画的情况下布置其子视图。这也是一个非常麻烦的修复,因为我需要将它添加到我能够覆盖的每个 UIView 对象中。

我仍然没有找到一劳永逸地解决这个问题的答案。如何仅对某事物的约束设置动画,但防止在其子视图上出现奇怪的不需要的动画。

【问题讨论】:

【参考方案1】:

我在 UICollectionView 中遇到了类似的问题,并且能够在其委托中修复它:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

    // setup your cell
    // ...

    [UIView performWithoutAnimation:^
        [cell layoutIfNeeded];
    ];

    return cell;

【讨论】:

这确实有帮助。 效果很好。但如果单元格包含辅助复选标记,复选标记将从左侧动画显示。我试图将此代码sn-p mv 到-tableView:willDisplayCell:forRowAtIndexPath:,解决了我的情况。希望对其他人有所帮助。【参考方案2】:

其他回答是正确的,但您必须在所有视图层次结构上都这样做。添加这个扩展方法,在不需要动画的**子视图**上调用。

public func commitSuperviewsLayout() 
    var processedSuperview = superview

    while processedSuperview != nil 
        processedSuperview?.layoutIfNeeded()
        processedSuperview = processedSuperview?.superview
    

【讨论】:

【参考方案3】:

奇怪的是,如果你把UIView.performWithoutAnimation 放在UIView.animate 之前,它就不起作用。如果你把它放在后面,它会起作用!顺序很重要:D

func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) 
    //        print("I am being edited")
    
    if self.searchCancelButton.isHidden 
        UIView.animate(withDuration: 0.2) 
            self.searchCancelButton.isHidden.toggle()
            self.topStack.layoutIfNeeded()
        
    
    
    UIView.performWithoutAnimation 
        self.state = .searchFoodView
        refreshEmptySearchFoodView()
    

【讨论】:

【参考方案4】:

一般来说,如果我只想为某些东西设置动画而不是其他的,我会确保设置所有不应设置动画的约束,然后调用

[view layoutIfNeeded]

在受这些约束影响的视图的父视图上。

最后我在我想要动画和调用的约束上设置了常量

[UIView animateWithDuration:0.2 animations:^ [view layoutIfNeeded];];

【讨论】:

但有时我只需要改变一个tableView的高度。我正在设置一个约束。其余的动画超出了我的控制范围。 @iseletsky 指的是系统在您展开视图并且最初具有 0 高度或 0 宽度时所做的动画,它不仅会为您正在展开的一侧设置动画,它还会为另一侧的变化设置动画,或者如果您实例化一个笔尖,它会为从原始大小到新大小的重新调整设置动画。

以上是关于在为约束设置动画时防止子视图上出现不需要的动画的主要内容,如果未能解决你的问题,请参考以下文章

动画 UITableView 宽度约束

iOS - 子视图不使用帧更改进行动画处理

在为 `tableHeaderView` 设置动画时为 `UITableView` 标头设置动画

iPhone:在为导航栏显示/隐藏设置动画时无法为 contentInset 设置动画

通过动画调整 UIView 大小时约束不起作用

如何为输入附件视图的高度设置动画?