【问题标题】:Determine when UIView has finished layout确定 UIView 何时完成布局
【发布时间】:2017-09-17 04:54:54
【问题描述】:

我有 UIView 子类,并且为了布局 UI 元素,我不使用自动布局。我想设置框架取决于框架的宽度或高度。但是,当我在 alloc]init] 方法之后立即执行此操作时,看起来 self.frame.size.height 或宽度为零。对于临时解决方案,我做了以下操作:

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.25 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        UIImage *img = [UIImage imageNamed:@"sound_level_arrow"];
        _arrowImgView = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.width/2, 0, img.size.width, img.size.height)];
        _arrowImgView.center = CGPointMake(self.mainImgView.frame.size.width/2, self.mainImgView.frame.size.height-2);
        _arrowImgView.image = [UIImage imageNamed:@"sound_level_arrow"];
        _arrowImgView.contentMode   = UIViewContentModeCenter;
        [self.mainImgView addSubview:_arrowImgView];
    });

但我当然需要知道,视图何时完成加载以及它的实际 self.frame.size.width 和高度在哪里。

【问题讨论】:

  • 你看过- (void)viewDidLayoutSubviews;吗?苹果参考:developer.apple.com/reference/uikit/uiviewcontroller/…
  • @DonMag 那是视图控制器,不是视图。
  • 你的初始化器真的设置了self的大小吗?
  • 如果您只是在这里用谷歌搜索试图在 UIView 中执行您可以在视图控制器中执行的操作,在 某些 情况下,didMoveToSuperview 是解决方案。

标签: ios objective-c uiview


【解决方案1】:

如果您想在自定义视图子类中执行此操作,请覆盖该类中的 layoutSubviews。由于 iOS 可能会多次发送layoutSubviews,请注意只在第一次创建_arrowImgView

- (void)layoutSubviews {
    [super layoutSubviews];

    if (_arrowImgView == nil) {
        UIImage *image = [UIImage imageNamed:@"sound_level_arrow"];
        _arrowImgView = [[UIImageView alloc] initWithImage:image];
        _arrowImgView.contentMode = UIViewContentModeCenter;
        [self addSubview:_arrowImgView];
    }

    CGRect myBounds = self.bounds;
    CGRect mainFrame = self.mainImageView.frame;
    _arrowImgView.bounds = CGRectMake(0, 0, myBounds.size.width, myBounds.size.height);
    _arrowImgView.center = CGPointMake(mainFrame.size.width / 2, mainFrame.size.height - 2);
}

【讨论】:

  • 我觉得你建议在 layoutSubviews 中创建和添加子视图很奇怪。不应该在适当的init 方法中完成吗? layoutSubviews 应该这样做 - 布局子视图。除了设置它们的框架之外,它不是创建、显示、隐藏或更改子视图的地方。
  • 请允许我引用the “Tweaking the Layout of Your Views Manually” section of the View Programming Guide for iOS:“您对这个方法的实现可以执行以下任何操作:……添加或删除子视图或核心动画层。”
  • 谢谢。我以前没有注意到这一点。在过去的十年里,我一直认为该方法应该只用于设置框架。
  • 也就是说,我通常会在init 中创建并添加子视图。
  • @robmayoff 它确实有效,但我想知道为什么这么简单的事情这么复杂。也许创建 UIView 的子类并使用 KVO 检查它的视图的宽度和高度是否大于 0 是个好主意,然后发送火灾通知并调用诸如“viewDidFinishLayoutItSubviews * 之类的方法并取消订阅通知。我使用 KVO 机制来检查 tableView 何时完成加载并且大小大于 0。
【解决方案2】:

使用这个。它处理方向变化和渐变背景的重绘。

import UIKit

@IBDesignable
final class GradientButton: UIButton {

    @IBInspectable var startColor: UIColor = UIColor.clear
    @IBInspectable var endColor: UIColor = UIColor.clear

    override func draw(_ rect: CGRect) {

        if let gradient = layer.sublayers?.first as? CAGradientLayer {
            gradient.removeFromSuperlayer()
        }

        let gradient: CAGradientLayer = CAGradientLayer()
        gradient.frame = CGRect(origin: CGPoint.zero, size: self.frame.size)
        gradient.colors = [startColor.cgColor, endColor.cgColor]
        layer.insertSublayer(gradient, at: 0)

        super.draw(rect)
    }

   @IBInspectable var imageContentMode: Int {
        get {
            return imageView?.contentMode.rawValue ?? 0
        }
        set {
            imageView?.contentMode = UIViewContentMode(rawValue: newValue) ?? .scaleAspectFit

        }
    }
}

【讨论】:

  • 我不记得 WWDC 但苹果说不要在 drawRect 中添加图层/视图。想法是配置这些元素,然后让布局和渲染通道处理它们。
【解决方案3】:

当'图层操作'例如添加边框需要视图的最终大小时,您可以使用(在swift 4中):

override func layoutSublayers(of layer: CALayer) {
    super.layoutSublayers(of: layer)
    // 'layer operations'
}

我正在努力通过一个函数只在底部添加一个边框, 我遇到了边框比按钮的最终宽度短的问题。

我把这个留给那些遇到同样问题并尝试过layoutSubviews但没有解决问题的人。

【讨论】:

    【解决方案4】:

    viewWillLayoutSubviews 和最后一个 viewDidLayoutSubviews

    - (void)viewDidLayoutSubviews {
       [super viewDidLayoutSubviews];
       // your code for positioning any subview here
    }
    

    【讨论】:

    • 这是一个视图控制器,而不是一个视图。
    • 请检查 UIView 和 ViewController 的区别。我建议您必须查看@IBDesignables,您必须在 UIView 中调用此方法希望我足够清楚
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    相关资源
    最近更新 更多