使用UIView的sizeToFit方法时遇到了困难,无法实现预期效果。

38
当我向一个UIView添加子视图或者调整已存在的子视图大小时,我期望[view sizeToFit][view sizeThatFits]会反映出这些变化。然而,我的经验是sizeToFit没有任何作用,而sizeThatFits在改变前后返回相同的值。
我的测试项目只包含一个视图,并包含一个按钮。点击按钮将在视图中添加另一个按钮,然后调用容器视图上的sizeToFit方法。在添加子视图之前和之后,视图边界的信息会被输出到控制台。
- (void) logSizes {
 NSLog(@"theView.bounds: %@", NSStringFromCGRect(theView.bounds));
 NSLog(@"theView.sizeThatFits: %@", NSStringFromCGSize([theView sizeThatFits:CGSizeZero])); 
}

- (void) buttonTouched { 
 [self logSizes];
 UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
 btn.frame = CGRectMake(10.0f, 100.0f, 400.0f, 600.0f);
 [theView addSubview:btn];
 [theView sizeToFit];
 [self performSelector:@selector(logSizes) withObject:nil afterDelay:1.0];
}

输出为:

2010-10-15 15:40:42.359 SizeToFit[14953:207] theView.bounds: {{0, 0}, {322, 240}}
2010-10-15 15:40:42.387 SizeToFit[14953:207] theView.sizeThatFits: {322, 240}
2010-10-15 15:40:43.389 SizeToFit[14953:207] theView.bounds: {{0, 0}, {322, 240}}
2010-10-15 15:40:43.391 SizeToFit[14953:207] theView.sizeThatFits: {322, 240}

我一定是漏掉了什么。

谢谢。

4个回答

53

关于此问题,文档已经很清晰了。 -sizeToFit 实际上就是调用 -sizeThatFits: 方法(可能使用视图的当前大小作为参数),而 -sizeThatFits: 的默认实现几乎什么都不做(只是返回其参数)。

一些 UIView 的子类会重写 -sizeThatFits: 方法以执行更有用的功能(例如 UILabel)。如果您需要任何其他功能(例如调整视图大小以适应其子视图),则应该创建 UIView 的子类并重写 -sizeThatFits: 方法。


1
谢谢Ole。我应该更仔细地阅读文档,而不是只看依赖于UIView特定子类中覆盖行为的代码片段。 - FishesCycle
3
我很惊讶这里没有任何回答分享他们如何实现这样的覆盖。 - aleclarson

7
如果您不想覆盖UIView,可以使用扩展(extension)。
Swift:
extension UIView {

    func sizeToFitCustom () {
        var size = CGSize(width: 0, height: 0)
        for view in self.subviews {
            let frame = view.frame
            let newW = frame.origin.x + frame.width
            let newH = frame.origin.y + frame.height
            if newW > size.width {
                size.width = newW
            }
            if newH > size.height {
                size.height = newH
            }
        }
        self.frame.size = size
    }

}

相同的代码但是运行速度提升了3倍:
extension UIView {
    final func sizeToFitCustom() {
        var w: CGFloat = 0,
            h: CGFloat = 0
        for view in subviews {
            if view.frame.origin.x + view.frame.width > w { w = view.frame.origin.x + view.frame.width }
            if view.frame.origin.y + view.frame.height > h { h = view.frame.origin.y + view.frame.height }
        }
        frame.size = CGSize(width: w, height: h)
    }
}

0
        self.errorMessageLabel.text = someNewMessage;

    // We don't know how long the given error message might be, so let's resize the label + containing view accordingly
    CGFloat heightBeforeResize = self.errorMessageLabel.frame.size.height;

    [self.errorMessageLabel sizeToFit];

    CGFloat differenceInHeightAfterResize = self.errorMessageLabel.frame.size.height - heightBeforeResize;

    self.errorViewHeightContstraint.constant = kErrorViewHeightConstraintConstant + differenceInHeightAfterResize;

这对我有用。


0

您可以仅使用IB(xcode 4.5)来完成以下操作:

  1. 点击 UIView
  2. 在 Size inspector 中将 content hugging 拖动到 1(水平和垂直方向都要拖动)
  3. compression resistance 拖动到 1000(两个方向都要拖动)
  4. 在 UIView 的 constraints 下,点击 Width 并将 priority 更改为 250
  5. 对于 Height 也做同样的操作
  6. 您可以使用 UIViewinset 来控制左/右/上/下的填充

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接