我正在创建一个应用程序,其UILabel
中有一个问题,UITableView
中显示多项选择答案,每行显示多项选择。问题和答案会有所不同,所以我需要UITableView
这个高度是动态的。
我想找一张sizeToFit
来解决这个问题。表格的框架设置为其所有内容的高度。
有人可以就如何实现这一目标提出建议吗?
答案 0 :(得分:143)
其实我自己找到了答案。
我只是使用CGRect
tableView.frame
height
创建新的table.contentSize.height
将UITableView
的高度设置为其内容的height
。
由于代码修改了UI,因此不要忘记在主线程中运行它:
dispatch_async(dispatch_get_main_queue(), ^{
//This code will run in the main thread:
CGRect frame = self.tableView.frame;
frame.size.height = self.tableView.contentSize.height;
self.tableView.frame = frame;
});
答案 1 :(得分:51)
没有KVO,DispatchQueue或自行设置限制的Swift 5和4.2解决方案。
此解决方案基于Gulz's answer。
1)创建 list(map(lambda x: len(x.split(' ')), phrase))
的子类:
UITableView
2)在布局中添加import UIKit
final class ContentSizedTableView: UITableView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
并在所有方面设置约束。将其类设置为UITableView
。
3)你应该看到一些错误,因为故事板并没有采用我们的子类'考虑ContentSizedTableView
。通过打开大小检查器并将intrinsicContentSize重写为占位符值来解决此问题。这是设计时的重写。在运行时,它将使用我们的intrinsicContentSize
类
更新:更改了Swift 4.2的代码。如果您使用的是先前版本,请使用ContentSizedTableView
代替UIViewNoIntrinsicMetric
答案 2 :(得分:49)
快速解决方案
请按照以下步骤操作:
1-从故事板中设置表格的高度约束。
2-从故事板中拖出高度约束,并在视图控制器文件中为它创建@IBOutlet。
override func viewWillLayoutSubviews() {
super.updateViewConstraints()
self.tableHeight?.constant = self.table.contentSize.height
}
3-然后,您可以使用以下代码动态更改表的高度:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.viewWillLayoutSubviews()
}
<强>更新强>
如果为您剪切了最后一行,请尝试在willDisplay单元格函数中调用viewWillLayoutSubviews():
{{1}}
答案 3 :(得分:20)
我在iOS 7中尝试了这个,它对我有用
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView sizeToFit];
}
答案 4 :(得分:18)
在表视图上添加contentSize属性的观察者,并相应地调整帧大小
[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];
然后在回调中:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
CGRect frame = your_tableview.frame;
frame.size = your_tableview.contentSize;
your_tableview.frame = frame;
}
希望这会对你有所帮助。
答案 5 :(得分:8)
如果您不想自己跟踪表视图的内容大小更改,您可能会发现此子类很有用。
establishEquipmentStatus
答案 6 :(得分:5)
我在滚动视图中有一个表视图,并且必须计算tableView的高度并相应地调整它的大小。这些是我采取的步骤:
0)向你的scrollView添加一个UIView(可能会在没有这一步的情况下工作,但我这样做是为了避免任何可能的冲突) - 这将是你的表视图的包含视图。如果您执行此步骤,则将视图边框设置为tableview的视图边框。
1)创建UITableView的子类:
class IntrinsicTableView: UITableView {
override var contentSize:CGSize {
didSet {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
}
}
2)将Storyboard中的表视图的类设置为IntrinsicTableView:screenshot:http://joxi.ru/a2XEENpsyBWq0A
3)将heightConstraint设置为表视图
4)将表格的IBoutlet拖到ViewController
5)将表格高度约束的IBoutlet拖到ViewController
6)将此方法添加到ViewController中:
override func viewWillLayoutSubviews() {
super.updateViewConstraints()
self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height
}
希望这有帮助
答案 7 :(得分:2)
Swift 3,iOS 10.3
解决方案1:
只需将self.tableview.sizeToFit()
放入cellForRowAt indexPath
函数即可。确保将tableview高度设置得比您需要的更高。
如果您没有在tableview下面查看视图,这是一个很好的解决方案。但是,如果你有,底部tableview约束将不会更新(我没有尝试解决它,因为我提出了解决方案2)
示例:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell {
cell.configureCell(data: testArray[indexPath.row])
self.postsTableView.sizeToFit()
return cell
}
return UITableViewCell()
}
解决方案2: 在storyboard中设置tableview高度约束并将其拖到ViewController。如果您知道单元格的平均高度,并且知道数组包含多少元素,则可以执行以下操作:
tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0 // Let's say 90 is the average cell height
<强> *编辑:强>
在我尝试过的所有解决方案之后,他们每个人都在修复某些问题,但并非完全无法解决,this就是完全解释和解决这个问题的答案。
答案 8 :(得分:2)
如果你的contentSize不对,这是因为它基于estimatedRowHeight(自动),请在此之前使用
tableView.estimatedRowHeight = 0;
答案 9 :(得分:1)
如果使用AutoLayout,有一种更好的方法:更改确定高度的约束。只需计算表格内容的高度,然后找到约束并进行更改。这是一个例子(假设确定你的桌子高度的约束实际上是一个高度约束,关系为&#34; Equal&#34;):
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
for constraint in tableView.constraints {
if constraint.firstItem as? UITableView == tableView {
if constraint.firstAttribute == .height {
constraint.constant = tableView.contentSize.height
}
}
}
}
答案 10 :(得分:1)
Mimo's answer和Anooj VM 's answer两者都很棒但是如果你有一个很大的列表会有一个小问题,框架的高度可能会切断你的一些细胞。
因此。我已经修改了一点答案:
dispatch_async(dispatch_get_main_queue()) {
//This code will run in the main thread:
CGFloat newHeight=self.tableView.contentSize.height;
CGFloat screenHeightPermissible=(self.view.bounds.size.height-self.tableView.frame.origin.y);
if (newHeight>screenHeightPermissible)
{
//so that table view remains scrollable when 'newHeight' exceeds the screen bounds
newHeight=screenHeightPermissible;
}
CGRect frame = self.tableView.frame;
frame.size.height = newHeight;
self.tableView.frame = frame;
}
答案 11 :(得分:1)
这适用于我使用自动版式的情况,并且只有一个部分的表格视图。
func getTableViewContentHeight(tableView: UITableView) -> CGFloat {
tableView.bounds = CGRect(x: 0, y: 0, width: 300, height: 40)
let rows = tableView.numberOfRows(inSection: 0)
var height = CGFloat(0)
for n in 0...rows - 1 {
height = height + tableView.rectForRow(at: IndexPath(row: n, section: 0)).height
}
return height
}
我在设置自动版式时调用此函数(此处的示例使用SnapKit,但您知道了)
let height = getTableViewContentHeight(tableView: myTableView)
myTableView.snp.makeConstraints {
...
...
$0.height.equalTo(height)
}
我希望UITableView只与单元格的组合高度一样高;我遍历单元格并累积单元格的总高度。由于此时表视图的大小为CGRect.zero,因此我需要设置范围以遵守单元格定义的自动布局规则。我将大小设置为应该足够大的任意值。实际尺寸将在以后由自动版面系统计算。
答案 12 :(得分:1)
Swit 5
var tableViewHeight: NSLayoutConstraint?
tableViewHeight = NSLayoutConstraint(item: servicesTableView,
attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,
multiplier: 0.0, constant: 10)
tableViewHeight?.isActive = true
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
tableViewHeight?.constant = tableView.contentSize.height
tableView.layoutIfNeeded()
}
答案 13 :(得分:0)
Musa almatri的objc版本
(void)viewWillLayoutSubviews
{
[super updateViewConstraints];
CGFloat desiredHeight = self.tableView.contentSize.height;
// clamp desired height, if needed, and, in that case, leave scroll Enabled
self.tableHeight.constant = desiredHeight;
self.tableView.scrollEnabled = NO;
}
答案 14 :(得分:0)
您可以尝试使用此自定义AGTableView
使用故事板或以编程方式设置TableView高度约束。 (此类自动获取高度约束并将内容视图高度设置为yourtableview height)。
class AGTableView: UITableView {
fileprivate var heightConstraint: NSLayoutConstraint!
override init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
self.associateConstraints()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.associateConstraints()
}
override open func layoutSubviews() {
super.layoutSubviews()
if self.heightConstraint != nil {
self.heightConstraint.constant = self.contentSize.height
}
else{
self.sizeToFit()
print("Set a heightConstraint to Resizing UITableView to fit content")
}
}
func associateConstraints() {
// iterate through height constraints and identify
for constraint: NSLayoutConstraint in constraints {
if constraint.firstAttribute == .height {
if constraint.relation == .equal {
heightConstraint = constraint
}
}
}
}
}
注意如果设置高度有任何问题,请yourTableView.layoutSubviews()
。
答案 15 :(得分:0)
基于 fl034 的答案。但对于 Xamarin.iOS 用户:
[Register("ContentSizedTableView")]
public class ContentSizedTableView : UITableView
{
public ContentSizedTableView(IntPtr handle) : base(handle)
{
}
public override CGSize ContentSize { get => base.ContentSize; set { base.ContentSize = value; InvalidateIntrinsicContentSize(); } }
public override CGSize IntrinsicContentSize
{
get
{
this.LayoutIfNeeded();
return new CGSize(width: NoIntrinsicMetric, height: ContentSize.Height);
}
}
}
答案 16 :(得分:0)
如果希望表是动态的,则需要使用基于表内容的解决方案,如上所述。如果只想显示一个较小的表,则可以使用容器视图并在其中嵌入UITableViewController-UITableView将根据容器大小进行调整。
这避免了很多计算和布局调用。
答案 17 :(得分:0)
我在Swift 5中的解决方案是将tableView的高度约束设置为其contentSize.height
的大小,假设每次cellForRowAt
中生成一个单元格时都使用“自动布局”
tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height).isActive = true
答案 18 :(得分:0)
我做了一些不同的事情,实际上我的TableView在scrollview内部,所以我不得不将高度限制设为0。
然后在运行时进行以下更改,
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.viewWillLayoutSubviews()
}
override func viewWillLayoutSubviews() {
super.updateViewConstraints()
self.tableViewHeightConstraint?.constant = self.myTableView.contentSize.height
}
答案 19 :(得分:0)
Swift 5解决方案
请遵循以下四个步骤:
从情节提要中设置表格视图的高度限制。
从情节提要中拖动高度约束,然后在视图控制器文件中为其创建@IBOutlet
。
@IBOutlet var tableViewHeightConstraint: NSLayoutConstraint!
在override func viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
}
然后您可以使用以下代码动态更改桌子的高度:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if(keyPath == "contentSize"){
if let newvalue = change?[.newKey]
{
DispatchQueue.main.async {
let newsize = newvalue as! CGSize
self.tableViewHeightConstraint.constant = newsize.height
}
}
}
}
答案 20 :(得分:0)
我正在使用 UIView扩展,方法与上面的@ChrisB方法接近
admin.database().ref('/113882052')
实现::
admin.database().ref()
奖金:可以在任何其他UIView上使用,例如:您自己的动态标签
答案 21 :(得分:-1)
在swift 3中解决此问题:在viewDidAppear
中调用此方法
func UITableView_Auto_Height(_ t : UITableView)
{
var frame: CGRect = t.frame;
frame.size.height = t.contentSize.height;
t.frame = frame;
}
答案 22 :(得分:-1)
作为Anooj VM的答案的扩展,我建议以下内容仅在更改时刷新内容大小。
此方法还正确禁用滚动,支持更大列表和轮换。不需要dispatch_async,因为在主线程上调度了contentSize更改。
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL];
}
- (void)resizeTableAccordingToContentSize:(CGSize)newContentSize {
CGRect superviewTableFrame = self.tableView.superview.bounds;
CGRect tableFrame = self.tableView.frame;
BOOL shouldScroll = newContentSize.height > superviewTableFrame.size.height;
tableFrame.size = shouldScroll ? superviewTableFrame.size : newContentSize;
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.tableView.frame = tableFrame;
} completion: nil];
self.tableView.scrollEnabled = shouldScroll;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([change[NSKeyValueChangeKindKey] unsignedIntValue] == NSKeyValueChangeSetting &&
[keyPath isEqualToString:@"contentSize"] &&
!CGSizeEqualToSize([change[NSKeyValueChangeOldKey] CGSizeValue], [change[NSKeyValueChangeNewKey] CGSizeValue])) {
[self resizeTableAccordingToContentSize:[change[NSKeyValueChangeNewKey] CGSizeValue]];
}
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
[self resizeTableAccordingToContentSize:self.tableView.contentSize]; }
- (void)dealloc {
[self.tableView removeObserver:self forKeyPath:@"contentSize"];
}