【问题标题】:AutoLayout Dynamic .xib View HeightAutoLayout 动态 .xib 视图高度
【发布时间】:2015-03-07 05:56:48
【问题描述】:

我无法通过单个 .xib 文件找到很多 AutoLayout 方式...

我有一个独立的 .xib 文件,它有 3 个视图 - 一个标题视图(包含两个标签)、一个输入和一个页脚(包含两个按钮)。它看起来像这样:

标题视图中的标签具有约束,这些约束会影响标题视图的垂直大小,进而影响整个视图的大小。副标题是一个 0 行的标签,这意味着它是多行和动态的。其他所有东西都有一个固定的高度,水平约束到超级视图和顶部约束到兄弟(或标题视图中的超级视图)。

我遇到的问题是,当我在代码中加载此 .xib 文件以进行显示时,高度始终是静态的,基于 Xcode 检查器中定义的内容。是否可以根据宽度使整个视图的高度动态化(这会影响动态标签高度并因此影响视图的其余部分)?

例如 - 如果我从 .xib 加载此视图并将其宽度设置为 300,那么我如何让它调整其高度以适应动态标签的新高度?我需要使用intrinsicContentSize 方法来定义这个大小吗?

【问题讨论】:

    标签: ios objective-c autolayout


    【解决方案1】:

    经过大量的实验和阅读,我找到了答案。在某种构造函数中加载 .xib 时(在我的例子中是类级别的便捷方法),您必须确保调用 [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 例如,我做了以下操作:

    + (InputView *)inputViewWithHeader:(NSString *)header subHeader:(NSString *)subHeader inputValidation:(ValidationBlock)validation
    {
        InputView *inputView = [[[NSBundle mainBundle] loadNibNamed:@"InputView" owner:self options:nil] lastObject];
        if ([inputView isKindOfClass:[InputView class]]) {
            [inputView setTranslatesAutoresizingMaskIntoConstraints:NO];
            [inputView configureWithHeader:header subHeader:subHeader inputValidation:validation];
            [inputView layoutIfNeeded];
            [inputView invalidateIntrinsicContentSize];
            return inputView;
        }
        return nil;
    }
    

    然后,有必要覆盖layoutSubviewsintrinsicContentSize。覆盖layoutSubviews 允许我设置标签的preferredMaxLayoutWidth,而覆盖intrinsicContentSize 允许我根据约束和子视图计算大小!这是我的实现:

    - (void)layoutSubviews {
        [super layoutSubviews];
        self.subHeaderLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
        [super layoutSubviews];
    }
    
    - (CGSize)intrinsicContentSize {
        CGFloat height = self.headerView.bounds.size.height;
        height += self.headerInputSpacer.constant;
        height += self.inputField.bounds.size.height;
        height += self.inputButtonSpacer.constant;
        height += self.buttonView.bounds.size.height;
        CGSize size = CGSizeMake([UIScreen mainScreen].bounds.size.width - 20, height);
        return size;
    }
    

    我确信有办法改进这一点,或者有更好的方法来实现它,但现在至少它的大小是正确的!对于不应具有用户定义框架的视图非常有用。

    【讨论】:

    • 你为什么要给layoutSubviews打两次电话?
    • 我试过了,但对我不起作用。你能把演示贴到 GitHub 上吗?非常感谢~
    • @Neko 请尝试下面列出的我的解决方案。
    【解决方案2】:

    这是我的方法(Swift 版本):

    将所有内容嵌入视图中。您的 xib 层次结构应该是:

    • 你的xib
      • 查看
        • 其他一切,您的标签、按钮等。

    视图的约束应该约束到TopLeadingTrailingsuperview(你的xib),并且在你的“其他一切”中,应该有一个对象的bottom 约束到超级视图(视图)。

    在您的代码中:

    加载笔尖

    nib.frame.size.width = 80 // Set your desired width here
    
    nib.label.text = "hello world" // Set your dynamic text here
    
    nib.layoutIfNeeded() // This will calculate and set the heights accordingly
    
    nib.frame.size.height = nib.view.frame.height + 16 // 16 is the total of top gap and bottom gap of auto layout
    

    就我而言,我将此 xib 加载到集合视图的单元格中,xib 的高度将动态调整,宽度将跟随单元格的宽度。最后,上面的代码块在我的集合视图的cellForItemAt 方法中。

    希望对你有帮助。

    【讨论】:

    • layoutIfNeeded() 节省了一天。
    【解决方案3】:

    很遗憾,我不确定自己错过了什么。上述方法不适用于我获取 xib 单元格的高度或让 layoutifneeded(), UITableView.automaticDimension 进行高度计算。我一直在寻找和尝试 3 到 4 晚,但没有答案。 此处或另一篇文章中的一些答案确实为我提供了解决方法的提示。这是一种愚蠢的方法,但它有效。只需将所有单元格添加到数组中。然后在 xib 故事板中设置每个高度约束的出口。最后,将它们添加到 heightForRowAt 方法中。如果您不熟悉这些 API,这很简单。

    斯威夫特 4.2

    CustomCell.Swift

    @IBOutlet weak var textViewOneHeight: NSLayoutConstraint!
    @IBOutlet weak var textViewTwoHeight: NSLayoutConstraint!
    @IBOutlet weak var textViewThreeHeight: NSLayoutConstraint!
    
    @IBOutlet weak var textViewFourHeight: NSLayoutConstraint!
    @IBOutlet weak var textViewFiveHeight: NSLayoutConstraint!
    

    MyTableViewVC.Swift

    .
    .
    var myCustomCells:[CustomCell] = []
    .
    .
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell
    
    .
    .
    myCustomCells.append(cell)
    return cell
    
    }
    
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    
       let totalHeight = myCustomCells[indexPath.row].textViewOneHeight.constant + myCustomCells[indexPath.row].textViewTwoHeight.constant +  myCustomCells[indexPath.row].textViewThreeHeight.constant + myCustomCells[indexPath.row].textViewFourHeight.constant + myCustomCells[indexPath.row].textViewFiveHeight.constant
    
      return totalHeight + 40 //some magic number
    
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 2014-10-18
      • 1970-01-01
      • 2015-07-04
      • 2019-09-04
      相关资源
      最近更新 更多