动态改变 UITableView 高度

Posted

技术标签:

【中文标题】动态改变 UITableView 高度【英文标题】:Change UITableView height dynamically 【发布时间】:2012-12-22 20:00:56 【问题描述】:

我想根据单元格高度的总和从另一个视图控制器更改我的表格视图的高度,因为它们是动态的。有可能吗?谢谢

插件:

我基本上拥有的是一个 UserProfileViewController,它在屏幕的一半上有一个容器视图。在那里我添加了不同的其他视图控制器:

在墙上按钮的情况下,这是我添加视图控制器及其后续表格视图的方式:

- (IBAction)wallButtonPressed:(id)sender

    //Check if there is an instance of the viewcontroller we want to display. If not make one and set it's tableview frame to the container's view bounds
    if(!_userWallViewController) 
        self.userWallViewController = [[WallViewController alloc] init];
//        self.userWallViewController.activityFeedTableView.frame = self.containerView.bounds;

    

    [self.userWallViewController.containerView addSubview:self.userWallViewController.activityFeedTableView];
    //If the currentviewcontroller adn it's view are already added to the hierarchy remove them
    [self.currentViewController.view removeFromSuperview];
    [self.currentViewController removeFromParentViewController];

    //Add the desired viewcontroller to the currentviewcontroller
    self.currentViewController = self.userWallViewController;

    //Pass the data needed for the desired viewcontroller to it's instances
    self.userWallViewController.searchURLString = [NSString stringWithFormat:@"event/user/%@/", self.userID];
    self.userWallViewController.sendCommentURLString = [NSString stringWithFormat:@"event/message/%@", self.userID];

    [self.userWallViewController.activityFeedTableView reloadData];

    self.userWallViewController.totalCellHeight = ^(float totalCellHeight)

        self.scrollView.contentSize = CGSizeMake(320.0, totalCellHeight);
        CGRect newFrame = self.userWallViewController.containerView.frame;
        newFrame.size.height = totalCellHeight + 33.0;
        self.userWallViewController.containerView.frame = newFrame;

        self.userWallViewController.activityFeedTableView.frame = self.containerView.bounds;
    ;

    //Add this containerview to the desired viewcontroller's containerView
    self.userWallViewController.containerView = self.containerView;


    //Add the needed viewcontroller and view to the parent viewcontroller and the containerview
    [self addChildViewController:self.userWallViewController];
    [self.containerView addSubview:self.userWallViewController.view];

    //CLEAN UP THE CONTAINER VIEW BY REMOVING THE PREVIOUS ADDED TABLE VIEWS
    [self.userFansViewController.userSimpleTableView removeFromSuperview];
    [self.fanOfViewController.userSimpleTableView removeFromSuperview];
    [self.userPublishedMovellaListViewController.gridView removeFromSuperview];

    [self.userPublishedMovellaListViewController removeFromParentViewController];

    self.userPublishedMovellaListViewController = nil;

在那个视图控制器中,这是我初始化我的 tableview 的地方:

-(UITableView *)activityFeedTableView

    if (!_activityFeedTableView) 
        _activityFeedTableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 850.0) style:UITableViewStylePlain];
    
    return _activityFeedTableView;

我正在计算单元格高度的总和,问题是单元格的高度方法是在调用 te tableview 的 getter 之后调用的。所以我需要某种方法来知道何时对所有单元格完成单元格的高度方法,然后我可以调整我的表格视图的大小。谢谢

【问题讨论】:

当然,如果您可以访问 tableview,行数,行高等。您需要做的就是 [otherVC.tableView setFrame:CGRectMake(originX,originY,width,height) ]; @Srikanth 正确,但这仅在您不使用自动布局时才有效。如果使用自动布局,则必须更改视图的约束。 Alex,您是否使用自动布局(仅适用于有效的 ios 6)?在回答你的问题时,你不能让它自动调整 tableview 的高度,而不是自己以编程方式这样做。根据您是否使用 iOS 6 的自动布局,解决方案会略有不同。 这段代码提出了许多超出可接受 cmets 范围的问题(因为它高度本地化,特定于这个特定的 sn-p 代码)。所以,我创建了一个聊天:chat.***.com/rooms/22461/… 【参考方案1】:

没有系统功能可以根据表格视图的内容更改表格的高度。话虽如此,可以根据内容以编程方式更改 tableview 的高度,特别是基于 tableview 的contentSize(这比自己手动计算高度更容易)。一些细节会根据您是否使用 iOS 6 中的新自动布局而有所不同。

但假设您在viewDidLoad 中配置表格视图的底层模型,如果您想随后调整表格视图的高度,您可以在viewDidAppear 中执行此操作:

- (void)viewDidAppear:(BOOL)animated

    [super viewDidAppear:animated];

    [self adjustHeightOfTableview];

同样,如果您曾经为 tableview 执行过 reloadData(或以其他方式添加或删除行),您需要确保也在那里手动调用 adjustHeightOfTableView,例如:

- (IBAction)onPressButton:(id)sender

    [self buildModel];
    [self.tableView reloadData];

    [self adjustHeightOfTableview];

所以问题是我们的adjustHeightOfTableview 应该做什么。不幸的是,这取决于您是否使用 iOS 6 自动布局。您可以通过打开情节提要或 NIB 并转到“文件检查器”来确定是否打开了自动布局(例如按 option+command+1 kbd> 或单击右侧面板上的第一个选项卡):

让我们暂时假设自动布局已关闭。在这种情况下,这很简单,adjustHeightOfTableview 只会调整 tableview 的frame

- (void)adjustHeightOfTableview

    CGFloat height = self.tableView.contentSize.height;
    CGFloat maxHeight = self.tableView.superview.frame.size.height - self.tableView.frame.origin.y;

    // if the height of the content is greater than the maxHeight of
    // total space on the screen, limit the height to the size of the
    // superview.

    if (height > maxHeight)
        height = maxHeight;

    // now set the frame accordingly

    [UIView animateWithDuration:0.25 animations:^
        CGRect frame = self.tableView.frame;
        frame.size.height = height;
        self.tableView.frame = frame;

        // if you have other controls that should be resized/moved to accommodate
        // the resized tableview, do that here, too
    ];

如果你的自动布局开启,adjustHeightOfTableview 会为你的 tableview 调整高度约束:

- (void)adjustHeightOfTableview

    CGFloat height = self.tableView.contentSize.height;
    CGFloat maxHeight = self.tableView.superview.frame.size.height - self.tableView.frame.origin.y;

    // if the height of the content is greater than the maxHeight of
    // total space on the screen, limit the height to the size of the
    // superview.

    if (height > maxHeight)
        height = maxHeight;

    // now set the height constraint accordingly

    [UIView animateWithDuration:0.25 animations:^
        self.tableViewHeightConstraint.constant = height;
        [self.view setNeedsUpdateConstraints];
    ];

为了使后一种基于约束的解决方案与自动布局一起使用,我们必须首先处理一些事情:

    通过单击此处按钮组中的中心按钮,确保您的 tableview 具有高度约束,然后选择添加高度约束:

    然后为该约束添加一个IBOutlet

    确保您调整其他约束,以便在您以编程方式调整大小 tableview 时它们不会发生冲突。在我的示例中,tableview 有一个尾随空间约束,将其锁定到屏幕底部,因此我必须调整该约束,以便它不会被锁定在特定大小,而是可能大于或等于一个值,并且具有较低的优先级,因此 tableview 的高度和顶部将统治这一天:

    您在此处对其他约束执行的操作将完全取决于您在表格视图下方的屏幕上拥有的其他控件。与往常一样,处理约束有点尴尬,但它确实有效,尽管你的具体情况完全取决于你在现场还有什么。但希望你能明白。最重要的是,使用自动布局,请确保调整您的其他约束(如果有)以灵活地考虑变化的 tableview 高度。

如您所见,如果您不使用自动布局,则以编程方式调整 tableview 的高度要容易得多,但如果您使用,我会提供两种选择。

【讨论】:

哇。这一定是我收到的最好的结构化答案。非常感谢。问题是我的应用程序也支持 ios 5,所以即使我很高兴我从你的回答中学到了一些东西,我也不能真正使用该功能。我已经更新了我的问题。你能看一下吗。谢谢 @alex 好吧,答案都是一样的,只是没有那种愚蠢的约束。只需使用adjustHeightOfTableView 的第一个版本就可以了。 我试过你回答关闭自动布局但不幸的是我的表格视图根本没有显示:( @Dejel:检查您是否在 viewDidAppear 而不是 viewDidLoad 中执行 [self adjustHeightOfTableView]。 只需将我们的应用程序升级到 AutoLayout(放弃对 iOS5 的支持)和新的 NSLayoutConstraint,一旦设置,就可以很好地替代设置框架。【参考方案2】:

通过 xib 或故事板创建您的单元格。给出它的出口内容。 现在在 CellForRowAtIndexPath 中调用它。 例如。如果要根据评论的标签文本设置单元格高度。

所以设置你 cmetsLbl.numberOfLine=0;

所以设置你 cmetsLbl.numberOfLine=0;

然后在 ViewDidLoad 中

 self.table.estimatedRowHeight = 44.0 ;
self.table.rowHeight = UITableViewAutomaticDimension;

现在

-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
return UITableViewAutomaticDimension;

【讨论】:

谢谢,成功了。实现这个答案后,我从以下链接“appcoda.com/self-sizing-cells”添加了“覆盖 func viewDidAppear(animated: Bool) tableView.reloadData()”这段代码 - 然后我在单元格中调整了行的大小 UITextView 没有numberOfLine 属性呢 @János UITextView 自动调整高度,如果你固定大小,textView 中的滚动将被启用。 谢谢。这节省了我几个小时。 出色的工作@Mohittomar【参考方案3】:

这里的很多答案都不尊重表格的变化,或者太复杂了。使用自动布局时,使用将正确设置intrinsicContentSizeUITableView 的子类是一个更容易的解决方案。不需要高度限制等。

class UIDynamicTableView: UITableView

    override var intrinsicContentSize: CGSize 
        self.layoutIfNeeded()
        return CGSize(width: UIViewNoIntrinsicMetric, height: self.contentSize.height)
    

    override func reloadData() 
        super.reloadData()
        self.invalidateIntrinsicContentSize()
    
 

在界面构建器中将您的 TableView 的类设置为 UIDynamicTableView 并观察魔术,因为此 TableView 将在调用 reloadData() 后更改其大小。

【讨论】:

这很好。为了更完整,它还可以处理最大值。 谢谢。我更喜欢使用 lessOrEqual 高度约束设置最大值。这样类就保持非常简单,您可以从界面构建器中设置最大简单。 intrinsicContentSize 将被使用,除非它超出了您的 lessOrEqual 约束。然后将启用滚动。 您的代码对我不起作用我收到错误消息:“参数标签 '(_:, _:)' 与任何可用的重载都不匹配 很棒的答案!几天来我一直在寻找这个解决方案。希望我能投票 5 到 6 次。 可能的改进:height: self.contentSize.height + self.contentInset.top + self.contentInset.bottom【参考方案4】:

这可以通过 viewDidAppear 中的 1 行代码进行大规模简化:

    override func viewDidAppear(animated: Bool) 
        super.viewDidAppear(animated)

        tableViewHeightConstraint.constant = tableView.contentSize.height
    

【讨论】:

【参考方案5】:

Rob 的解决方案非常好,只是在他的-(void)adjustHeightOfTableview 方法中调用了

[self.view needsUpdateConstraints]

什么都不做,它只是返回一个标志,而不是调用

[self.view setNeedsUpdateConstraints]

会产生想要的效果。

【讨论】:

【参考方案6】:

为了调整我的表格大小,我在我的 tableview 控制器中使用了这个解决方案,非常好:

[objectManager getObjectsAtPath:self.searchURLString
                         parameters:nil
                            success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 
                                NSArray* results = [mappingResult array];
                                self.eventArray = results;
                                NSLog(@"Events number at first: %i", [self.eventArray count]);
                                CGRect newFrame = self.activityFeedTableView.frame;
                                newFrame.size.height = self.cellsHeight + 30.0;
                                self.activityFeedTableView.frame = newFrame;

                                self.cellsHeight = 0.0;

                            
                            failure:^(RKObjectRequestOperation *operation, NSError *error) 
                                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                                message:[error localizedDescription]
                                                                               delegate:nil
                                                                      cancelButtonTitle:@"OK"
                                                                      otherButtonTitles:nil];
                                [alert show];
                                NSLog(@"Hit error: %@", error);
                            ];

调整大小的部分在一个方法中,但这里只是为了让您可以看到它。 现在我唯一的问题是在另一个视图控制器中调整滚动视图的大小,因为我不知道 tableview 何时完成调整大小。目前我正在使用 performSelector: afterDelay: 来做这件事,但这真的不是一个好方法。有什么想法吗?

【讨论】:

【参考方案7】:

使用简单易行的代码

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 
        let myCell = tableView.dequeueReusableCellWithIdentifier("mannaCustumCell") as! CustomCell
        let heightForCell = myCell.bounds.size.height;

        return heightForCell;
    

【讨论】:

【参考方案8】:

我发现以编程方式添加约束比在情节提要中容易得多。

    var leadingMargin = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.LeadingMargin, relatedBy: NSLayoutRelation.Equal, toItem: self.mView, attribute: NSLayoutAttribute.LeadingMargin, multiplier: 1, constant: 0.0)

    var trailingMargin = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.TrailingMargin, relatedBy: NSLayoutRelation.Equal, toItem: mView, attribute: NSLayoutAttribute.TrailingMargin, multiplier: 1, constant: 0.0)

    var height = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: screenSize.height - 55)

    var bottom = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: self.mView, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1, constant: screenSize.height - 200)

    var top = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.TopMargin, relatedBy: NSLayoutRelation.Equal, toItem: self.mView, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: 250)

    self.view.addConstraint(leadingMargin)
    self.view.addConstraint(trailingMargin)
    self.view.addConstraint(height)
    self.view.addConstraint(bottom)
    self.view.addConstraint(top)

【讨论】:

以上是关于动态改变 UITableView 高度的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 动态高度不改变 iOS

动态改变 UITableView 高度

UITableView:改变 TableHeaderView 的高度

改变 UITableView Customcell 的高度

UITableView:单击按钮时如何动态更改单元格高度?

动态改变 UITableViewCell 高度 - Swift 4