简体   繁体   English

AutoLayout Dynamic .xib查看高度

[英]AutoLayout Dynamic .xib View Height

I've not been able to find much in the way of AutoLayout with individual .xib files... 我无法通过单独的.xib文件找到AutoLayout的方式...

I've got a standalone .xib file that has 3 views - a header view (which contains two labels), an input, and a footer (which contains two buttons). 我有一个独立的.xib文件,有3个视图 - 标题视图(包含两个标签),一个输入和一个页脚(包含两个按钮)。 It looks like this: 它看起来像这样:

在此输入图像描述

The labels in the header view have constraints which should affect the vertical size of the header view, and in turn the size of the entire view. 标题视图中的标签具有约束,这些约束应该影响标题视图的垂直大小,进而影响整个视图的大小。 The subheader is a label with 0 lines, which means it is multi-line and dynamic. 子标题是一个带有0行的标签,这意味着它是多行和动态的。 Everything else has a set height with horizontal constraints to superview and top constraints to sibling (or superview in header view's case). 其他所有东西都有一个设置高度,水平约束到superview和顶部约束兄弟(或标题视图中的superview)。

The issue I am having is that when I load this .xib file in code for display, the height is always static based on what is defined in Xcode's inspectors. 我遇到的问题是,当我在代码中加载此.xib文件进行显示时,根据Xcode检查器中定义的内容,高度始终是静态的。 Is it possible to make the height of the entire view dynamic based on the width (which affects dynamic label height and therefore rest of the view)? 是否可以根据宽度使整个视图的高度动态变化(这会影响动态标签高度,从而影响视图的其余部分)?

For example - if I load this view from the .xib and set its width to 300, how do I then have it resize its height to accommodate the dynamic label's new height? 例如 - 如果我从.xib加载此视图并将其宽度设置为300,那么我如何调整其高度以适应动态标签的新高度? Do I need to use the intrinsicContentSize method to define this size? 我是否需要使用intrinsicContentSize方法来定义此大小?

After much experimentation and reading, I have found the answer. 经过大量的实验和阅读,我找到了答案。 When loading the .xib in some sort of constructor (in my case a class level convenience method), you must make sure to call [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 在某种构造函数中加载.xib(在我的情况下是一个类级别的方便方法),你必须确保调用[view setTranslatesAutoresizingMaskIntoConstraints:NO]; For example, I've done the following: 例如,我做了以下事情:

+ (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;
}

Then, it's necessary to override layoutSubviews and intrinsicContentSize . 然后,有必要覆盖layoutSubviewsintrinsicContentSize Overriding layoutSubviews allows me to set the preferredMaxLayoutWidth of my label, while overriding intrinsicContentSize allows me to calculate the size based on constraints and subviews! 覆盖layoutSubviews允许我设置我的标签的preferredMaxLayoutWidth ,而覆盖intrinsicContentSize允许我根据约束和子视图计算大小! Here is my implementation of those: 这是我的实现:

- (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;
}

I'm sure there are ways to improve this, or better ways to make it happen, but for now it is at least sized correctly! 我确信有很多方法可以改善这种情况,或者更好的方法来实现它,但是现在它的尺寸至少是正确的! Very useful for views that should not have user-defined frames. 对于不应具有用户定义帧的视图非常有用。

This is my approach (Swift version): 这是我的方法(Swift版本):

Embed everything inside a view. 将所有内容嵌入视图中。 Your xib hierarchy should be: 您的xib层次结构应该是:

  • Your xib 你的xib
    • View 视图
      • Everything else, your labels, buttons etc. 其他所有,你的标签,按钮等。

View's constraint should constraint to Top , Leading and Trailing to superview (your xib), and inside your "everything else", there should be an object's bottom constraint to the superview (View). 查看的约束应该约束到TopLeadingTrailingsuperview (您XIB),而你的“一切”里面,应该有一个对象的bottom约束到上海华(查看)。

In your code: 在你的代码中:

Load the nib 加载笔尖

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

For my case, I'm loading this xib into collection view's cell, the xib's height is to be dynamically adjusted, and the width is to follow cell's width. 对于我的情况,我将这个xib加载到集合视图的单元格中,xib的高度将被动态调整,宽度将遵循单元格的宽度。 Lastly, the above code block is inside my cellForItemAt method of the collection view. 最后,上面的代码块在我的集合视图的cellForItemAt方法中。

Hope it helps. 希望能帮助到你。

Unfortunately, I am not sure what I was missing. 不幸的是,我不确定我错过了什么。 The above methods don't work for me to get the xib cell's height or let the layoutifneeded(), UITableView.automaticDimension to do the height calculation. 上面的方法不适合我获取xib单元格的高度或让layoutifneeded(),UITableView.automaticDimension进行高度计算。 I've been searching and trying for 3 to 4 nights but without an answer. 我一直在寻找和尝试3到4晚,但没有答案。 Some answers here or on another post do give me hints for the workaround though. 这里或其他帖子的一些答案确实给了我解决方法的提示。 It's a stupid method but it works. 这是一个愚蠢的方法,但它的工作原理。 Just add all your cells into an Array. 只需将所有单元格添加到数组中。 And then set the outlet of each of your height constraint in the xib storyboard. 然后在xib故事板中设置每个高度约束的出口。 Finally, add them up in the heightForRowAt method. 最后,在heightForRowAt方法中添加它们。 It's just straight forward if you are not familiar with the those APIs. 如果您不熟悉那些API,那就是直截了当。

Swift 4.2 Swift 4.2

CustomCell.Swift 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 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


}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM