由于自动布局没有计算尺寸,将子视图添加到自定义视图最终会出错

Posted

技术标签:

【中文标题】由于自动布局没有计算尺寸,将子视图添加到自定义视图最终会出错【英文标题】:Adding subview to custom view ends up wrong due to auto layout haven't calculated dimensions 【发布时间】:2015-12-12 00:30:45 【问题描述】:

我创建了一个自定义视图类。我有一个想要模糊的图像视图。我在下面的代码中添加了模糊效果,但显然不起作用,因为图像视图是错误的。由于自动布局尚未计算出正确的图像视图高度和宽度尺寸。但是,我应该重写哪种方法来访问正确的位置和大小属性?

只添加一次的解决方案是什么?

class ProductListingCell: UICollectionViewCell 

    @IBOutlet weak var nameLabel: UILabel!    
    @IBOutlet weak var sharpImageView: UIImageView!
    @IBOutlet weak var blurImageView: UIImageView!

    override func awakeFromNib() 
        super.awakeFromNib()


        let blurEffect = UIBlurEffect(style: .Light)
        let visualEffectView = UIVisualEffectView(effect: blurEffect)
        visualEffectView.frame = blurImageView.bounds
        blurImageView.addSubview(visualEffectView)
    

(编辑)也许是一个答案:

在发布问题后,我发现了这种方法。这是正确的做法吗?

override func layoutSubviews() 
    super.layoutSubviews()

    layoutIfNeeded()
    let blurEffect = UIBlurEffect(style: .Light)
    let visualEffectView = UIVisualEffectView(effect: blurEffect)
    visualEffectView.frame = blurImageView.bounds
    blurImageView.addSubview(visualEffectView)

【问题讨论】:

layoutSubviews 是你想要的。您应该将其添加为答案。请注意,此方法可能会被多次调用,因此您需要保留对 visualEffectView 的引用并在再次调用时替换它。 由于您使用的是自动布局,因此您应该在代码中创建自动布局约束,而不是设置框架。 @TomHarrington 所以你会改变我设置 frame = bounds 的语句吗? @picciano 我也需要layoutIfNeeded() 电话是否正确? (没有它就行不通 - 很明显,但为什么呢?) @LuckyLuke 是的,只有您需要在添加子视图之后而不是之前创建约束。 【参考方案1】:

是的,你是正确的:layoutSubviews() 是要走的路。

但是,您不需要而且实际上也不应该在 layoutSubviews() 正文中使用 layoutIfNeeded()。这是因为layoutIfNeeded() 所做的是检查是否在视图上设置了特定的内部标志(它在您或系统调用setNeedsLayout() 时设置),如果是这种情况,它会在视图上调用layoutSubviews()(非常与您调用它的方法相同)。换句话说:如果您在调用layoutIfNeeded() 之前在layoutSubviews() 方法中执行任何使当前布局无效的操作,您可能会在此处创建一个永无止境的递归循环

我在示例项目中测试了使用和不使用layoutIfNeeded() 调用的代码,两种实现都产生了相同(正确)的结果。请检查您是否对代码进行了任何其他更改。

当在您的自定义视图上调用layoutSubviews() 时,您可以确定系统在解决了所有将视图约束到其兄弟视图及其父视图的布局约束后已设置视图的框架。但是,您需要先调用super.layoutSubviews() 才能正确定位视图的所有子视图。

【讨论】:

我遇到了与 OP 相同的问题,通常会给出与您给出的完全相同的建议。但是我最终不得不在 layoutSubviews 中调用 layoutIfNeeded 来更新我的所有子视图框架。这只是使用自动布局时的问题。

以上是关于由于自动布局没有计算尺寸,将子视图添加到自定义视图最终会出错的主要内容,如果未能解决你的问题,请参考以下文章

添加和布局从 xib 加载的子视图到自定义单元格

如何将子视图添加到自定义 UICollectionViewCell

将子视图添加到自定义 viewForHeaderInSection 会中断 VoiceOver 导航

如何使用自动布局(约束)将子视图添加到 UIPageViewController?

使用自动布局将子视图添加到 UITableView 不会设置其框架

以编程方式使用自动布局将子视图添加到 UICollectionView 不起作用