iOS 7 和 iOS 8 中动态 UITableViewCell 的高度是不可能的
Posted
技术标签:
【中文标题】iOS 7 和 iOS 8 中动态 UITableViewCell 的高度是不可能的【英文标题】:Dynamic UITableViewCell's height in iOS 7 AND iOS 8 impossible 【发布时间】:2014-11-25 16:09:39 【问题描述】:我很难尝试在 ios 7 和 8 下获得具有动态大小的单元格的表格视图。我无法详细说明要找到的所有差异(以“方式iOS 7 和 8 之间的损坏布局”),可以使用不同的“调整”、“解决方法”以及我在这里和其他地方找到的任何东西来生成。但最终在 iOS 7 或 iOS 8(如果不是两者)上,部分或全部单元格的内容未对齐,因为布局系统“打破”了“恢复”的自定义约束之一。
基本上我有三种不同类型的内容。由于我不仅在上述表格视图中显示这些内容,我还将这些内容包装在UIView
的三个子类中。让我们叫他们SummaryView
s
对于表格视图,然后我创建了UITableViewCell
的三个子类,每个子类都将相应的SummaryView
添加到其contentView
并设置self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
。在updateViewConstraints
上,我通常会删除之前可能已添加的所有“我的”约束并执行...
- (void)updateConstraints
// ...removed custom constraints before
NSDictionary *views = NSDictionaryOfVariableBindings(_summaryView);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_summaryView]-|"
options:0
metrics:nil
views:views]
toView:self.contentView];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_summaryView]-|"
options:0
metrics:nil
views:views]
toView:self.contentView];
[super updateConstraints];
在tableView:estimatedHeightForRowAtIndexPath:
中,我根据内容的类型返回一个静态估计值。
在tableView:heightForRowAtIndexPath:
中,我以...的方式使用“原型”单元格。
// ..set content on prototype cell before
[prototypeCell setNeedsUpdateConstraints];
[prototypeCell layoutIfNeeded];
CGSize size = [prototypeCell systemLayoutSizeFittingSize:UILayoutFittingExpandedSize];
return size.height;
这里调试器通常在UIViewAlertForUnsatisfiableConstraints
([prototypeCell layoutIfNeeded]
)上中断,<NSLayoutConstraint:0x17409f180 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x17019f070(44)]>
与其余约束冲突。
所以我尝试了...
在表视图的viewDidLoad
中设置tableView.rowHeight = UITableViewAutomaticDimension
未实现tableView:estimatedHeightForRowAtIndexPath:
使用...
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
...在应用单元格的内容并计算其布局之前
在单元初始化时执行self.contentView.bounds = CGRectMake(0.0, 0.0, 1000, 1000);
可能还有其他事情,我现在不记得了,因为我现在差不多两天了。
总是一样的,如果我实现了一个不抱怨不可满足的约束的变体,那么布局通常还是一团糟。虽然我让表格视图不设置“默认”<NSLayoutConstraint:0x17409f180 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x17019f070(44)]>
约束,但设置的约束(基于tableView:heightForRowAtIndexPath:
返回的高度)既不适合布局系统。
这篇文章是最后的手段。我知道如果没有具体视图类的约束,您将无法重新检查它们。但由于我可以在表视图之外毫无问题地使用这些视图,所以它不应该是子视图的约束问题。
我想我将不得不手动计算所有视图元素的大小(基于[UIScreen mainScreen].bounds
)并将它们直接设置(作为宽度和高度)到所有子视图。所以我可以得到一个单元格的具体高度,并且可以手动设置contentView
的框架。很可惜,因为它显着地弄乱了布局代码......
最好的问候, 加布里埃尔
【问题讨论】:
您走错了路,您的单元格的高度基于您通过–tableView:heightForRowAtIndexPath:
方法返回的值。这将定义屏幕上的实际高度。玩弄自动布局或自动调整大小蒙版无济于事。
@holex 你的狩猎声望? A:请随意告诉我(和其他人)什么是正确路径。 B:我认为tableView:heightForRowAtIndexPath
的用途从未有过任何疑问。 C:我不是玩弄自动布局,我实际上是在使用它。 D:与autoresizingMask
玩耍似乎帮助了其他人:***.com/a/19154287/981728。
【参考方案1】:
最后我找到了一个可以接受的解决方案,它不会过多地弄乱布局代码。 简而言之:
在表格视图单元格的updateConstraints
中,我将约束从_summaryView
-bottom 删除到superview-bottom。因此,内容视图的高度限制不会干扰摘要视图中的高度限制。
- (void)updateConstraints
NSDictionary *views = NSDictionaryOfVariableBindings(_summaryView);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_summaryView]-|"
options:0
metrics:nil
views:views]
toView:self.contentView];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_summaryView]"
options:0
metrics:nil
views:views]
toView:self.contentView];
[super updateConstraints];
在tableView:heightForRowAtIndexPath:
中,我只使用相关单元格的intrinsicContentSize
来获取高度:
[prototypeCell.summaryView applyStuff];
[prototypeCell layoutIfNeeded];
height = [prototypeCell intrinsicContentSize].height;
上述表格视图单元intrinsicContentSize
的实现如下:
- (CGSize)intrinsicContentSize
// Calculate the available content width if not done yet
static CGFloat availableWidth = 0.0;
if (availableWidth == 0.0)
availableWidth = CGRectGetWidth([UIScreen mainScreen].bounds);
// Check if the contentView's frame needs an update
if (CGRectGetWidth(self.contentView.frame) != availableWidth)
CGRect frame = CGRectMake(0.0, 0.0, availableWidth, 100.0);
self.contentView.frame = frame;
[_summaryView layoutIfNeeded];
CGSize size = _summaryView.frame.size;
size.height += 2.0 * V_PADDING;
size.width += 2.0 * H_PADDING;
return size;
请注意,对于支持纵向和横向模式的应用,availableWidth
必须在方向更改时重置,或者不应为static
。 *_PADDING
是我希望_summaryView
在所有方面都有的空间。
我还从单元的初始化代码中删除了self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth
。因为它似乎没有任何明显的效果。
【讨论】:
我感到你很沮丧,我正在使用类似的方法:不设置尾随约束,并通过将 self.view.frame.width (tableViewCell 由于UIView-Encapsulated-Layout-Width
) 应用到子视图的框架来计算它的高度......希望看看有没有人能想出一种方法让contentView框架完全由intrinsicContentSize计算,似乎仍然没有可能的解决方案。
我的tableView单元格有一个很大的UILabel,在tableView:heightForRowAtIndexPath:
,我使用contentLabelHeight = contentLabel.font.sizeOfString(contentLabel.text!, constrainedToWidth: Double(self.view.frame.width - 44)).height
先计算高度(第44页是你的2.0 * H_PADDING
)然后返回contentLabelHeight + contentLabel.frame .origin.y + 20(p.s. 20 是你的2.0 * V_PADDING
)
是的,iOS 7 下似乎没有 nice 处理“动态行高”的方法。【参考方案2】:
我可能在讨论中来晚了一点,但我遇到了类似的问题并找到了解决方案。
添加约束时,将它们添加到 contentView 而不是单元格。否则,“|-”和“-|”在视觉语言格式中会创建与单元格本身相关的约束,而我们糟糕的 contentView 将没有任何约束。
所以,不要使用[self addConstraints: ...];
,而是使用[self.contentView addConstraints: ...];
。
【讨论】:
_summaryView
是单元格的contentView
的子视图。向视图添加约束时,约束是指这个视图还是它的子视图并不重要。
我刚刚仔细检查以确保它是否有所不同(在我当前的项目中)——确实如此。任何带有“|-”或“-|”的视觉语言约束指接收 addConstraint 方法的容器。我还收到消息“检测到约束模糊地建议 tableview 单元格的内容视图高度为零的情况”,如果我将“addConstraint”发送到 contentView 而不是单元格,我不会收到消息。 iOS8.3下。
好吧,这将是一个解释。遗憾的是,我目前没有时间用我们的项目进行测试。但我会记住的,迟早我会检查的......以上是关于iOS 7 和 iOS 8 中动态 UITableViewCell 的高度是不可能的的主要内容,如果未能解决你的问题,请参考以下文章
在 IOS 8 中工作的具有动态高度的 UITableView 行在 ios 7 中不工作
使用 IOS9 时,无法在 UITable 的部分标题上的 UIButtons 上触发触摸事件(IOS10 很好)