动态单元高度自动布局 IOS

Posted

技术标签:

【中文标题】动态单元高度自动布局 IOS【英文标题】:Dynamic Cell Height autolayout IOS 【发布时间】:2015-05-31 20:17:17 【问题描述】:

我一直在按照本教程来实现动态单元格高度。 dynamic-table-view-cell-height 但它只适用于我的 ios 7 而不适用于 ios 8。但它确实适用于 iPAD 上的 ios 8,所以我有点难过为什么它不能在 iphone 上运行。虽然我已经非常准确地遵循了代码,但本教程和我实现它的方式之间存在一些差异,并且由于我对自动布局和表格了解不够,我不确定这是否是导致我的问题的原因。

首先在教程中,tableView 的后沿和前导边与父视图完全相等,为 0。在我的实现中,我创建了比例约束,以便在多个不同布局中缩放 tableView。进一步解释:

这是我的 TableView 的图片,它在多个不同的设备上使用了比例约束。

为了实现这一点,我实施了以下约束:

是否有可能因为tableView有动态高度,导致AutoLayout无法计算单元格高度?

我的实现和教程之间的第二个区别是数据源。我从调用 SLQ3Lite 数据库中获取数据,而本教程从 xml 提要中获取数据。我确信数据正在填充单元格,因为当我在 IPAD 上查看我的实现时,我可以看到如下数据:

但在 iphone 上显示的是: 表格可见,但没有单元格被写入表格。

当我使用调试器时,我可以看到记录已成功从数据库中检索到,但并未写入表中。

这里的代码很长(对不起)

    #import "favouritedViewController.h"
#import "DBManager.h"
#import "favouritedCell.h"

@interface favouritedViewController ()
@property (strong, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSArray *favourites;
@property (nonatomic, strong) DBManager *dbManager;
typedef void (^CompletionBlock)();

-(void)loadData;
-(void)reloadDataWithCompletions:(CompletionBlock)completionBlock;

@end

@implementation favouritedViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.dbManager = [[DBManager alloc] initWithDatabaseFilename:@"tomhaisdb.sql"];

    self.tableView.delegate = self;
    self.tableView.dataSource = self;

    [self loadData];



- (void)didReceiveMemoryWarning 
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


-(void)loadData 
    NSString *query = @"select * from favourites";

    if (self.favourites != nil) 
        self.favourites = nil;
    

    self.favourites = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];

   /* [self reloadDataWithCompletions:^
         self.tableView.backgroundColor = [UIColor colorWithRed:28.0f/255.0f green:30.0f/255.0f blue:35.0f/255.0f alpha:1];
    ];*/
    [self reloadTableViewContent];




/*-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    return 1;
*/

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    return self.favourites.count;



-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    return [self basicCellAtIndexPath:indexPath];


- (void)reloadTableViewContent 
    dispatch_async(dispatch_get_main_queue(), ^
        [self.tableView reloadData];
        [self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
    );


-(favouritedCell *)basicCellAtIndexPath:(NSIndexPath *)indexPath 
    favouritedCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"favouriteCell" forIndexPath:indexPath];
    [self configureBasicCell:cell atIndexPath:indexPath];
    return cell;


-(void)configureBasicCell:(favouritedCell *)cell atIndexPath:(NSIndexPath *)indexPath
    NSInteger indexOfTomhaisText = [self.dbManager.arrColumnNames indexOfObject:@"tomhaisText"];
    NSString *tomhaisText = [[self.favourites objectAtIndex:indexPath.row] objectAtIndex:indexOfTomhaisText];
    [self setTomhaisForCell:cell item:tomhaisText];
    [self setAnswerForCell:cell item:tomhaisText]; // change this later


-(void)setTomhaisForCell:(favouritedCell *)cell item:(NSString *)item
    [cell.favouriteText setText:item];


-(void)setAnswerForCell:(favouritedCell *)cell item:(NSString *)item
    [cell.answer setText:item];


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    return [self heightForFavouriteCellAtIndexPath:indexPath];


-(CGFloat)heightForFavouriteCellAtIndexPath:(NSIndexPath *)indexPath
    static favouritedCell *sizingCell = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        sizingCell = [self.tableView dequeueReusableCellWithIdentifier:@"favouriteCell"];
    );

    [self configureBasicCell:sizingCell atIndexPath:indexPath];
    return [self calculateHeightForConfiguredSizingCell:sizingCell];


-(CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell
    sizingCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.frame), CGRectGetHeight(sizingCell.bounds));
    [sizingCell setNeedsLayout];
    [sizingCell layoutIfNeeded];

    CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    return size.height + 1.0f;


-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
    return 155.0f;

编辑 1


这是它在 ios 7 上运行的图片(正在运行)

这是日志输出

2015-06-01 18:43:40.855 事实[62233:607] 行数:2 2015-06-01 18:43:43.996 Facts[62233:607] 布局前边界 0, 0, 256, 82 2015-06-01 18:43:55.068 Facts[62233:607] 布局前的内容视图 0, 0, 256, 82 2015-06-01 18:44:09.409 事实[62233:607] 界限 布局后 0, 0, 256, 82 2015-06-01 18:44:12.843 Facts[62233:607] 布局前的内容视图 0, 0, 256, 82 2015-06-01 18:44:21.462 Facts[62233:607] 布局 0, 0 之前的边界, 256, 82 2015-06-01 18:44:23.884 事实[62233:607] 内容视图 在布局 0, 0, 256, 82 2015-06-01 18:44:30.536 之前 Facts[62233:607] 布局后边界 0, 0, 256, 82 2015-06-01 18:44:32.278 Facts[62233:607] 布局 0, 0 之前的内容视图, 256, 82

从这段代码:

    -(CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell
    sizingCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.frame), CGRectGetHeight(sizingCell.bounds));
    NSLog(@"Bounds before Layout %@", NSStringFromCGRect(sizingCell.bounds));
     NSLog(@"Content View before Layout %@", NSStringFromCGRect(sizingCell.contentView.bounds));
    [sizingCell setNeedsLayout];
    [sizingCell layoutIfNeeded];

    CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    NSLog(@"Bounds after layout %@", NSStringFromCGRect(sizingCell.bounds));
    NSLog(@"Content View before Layout %@", NSStringFromCGRect(sizingCell.contentView.bounds));
    return size.height + 1.0f;

但在 ios8 上,我看到的是:

这是输出:

2015-06-01 18:47:14.688 Facts[62306:81355636] 布局前的界限 0, 0, 256, 44 2015-06-01 18:47:14.688 事实[62306:81355636] 布局前的内容视图 0, 0, 256, 44 2015-06-01 18:47:14.688 Facts[62306:81355636] 布局后边界 0, 0, 256, 44 2015-06-01 18:47:14.688 Facts[62306:81355636] 之前的内容查看 布局 0, 0, 256, 44

ios7 中的 sizingCell 正在读取单元格内容的正确边界,但在 ios8 中却不是。

【问题讨论】:

您能否展示您对单元格/标签的约束? 【参考方案1】:

我发现https://github.com/forkingdog/UITableView-FDTemplateLayoutCell 库很有用。我已经尝试了所有但没有工作。现在这个库会动态计算 UITableView 行的高度。

【讨论】:

【参考方案2】:

你做的太多了; Apple 可以为您处理前导和尾随间距。

0 正是要使用的正确号码,但您固定到superview.margin,而不是superview。 Apple 会根据设备为您调整边距,使其达到推荐的边距。 (4.7 英寸更宽,4 英寸更窄。)

仅供参考,0 乘以任何乘数始终为 0,因此您当前的约束不会达到您预期的效果。

单元格高度关闭的原因是错误放置的框架(Interface Builder 无法发出警告,因为没有为 anyXany 安装标签约束)。

IOS 7 仍然可以解决单元格高度,但iOS 8 requires the cell height to be initially correct(可解决)。

【讨论】:

我不确定我是否理解您的回答。我不是乘以 0,而是乘以第二个项目,即 .center X,这将是 0.5 - 所以在前导空格 .2 * .5 = .1 的情况下,前导空格将是 10%屏幕的宽度。同样,尾随空格是乘数 1.8 乘以 center.x 或 .5 = .9 或将与设备宽度的 90% 对齐。所以我不认为这是我的尾随或前导空格 - 它也适用于 ios7 但不适用于 io8 对不起,问题太多了!您对 tableView 是正确的。对于单元格,您确实希望 0 作为前导/尾随空间,并让系统处理边距。表格高度可以改变的事实不会影响单元格高度计算。他们是完全独立的。 是的,我很感激——这可能是 *** 上最严重的问题。我很感激你花时间看它。我在底部添加了一个编辑,其中包含单元格内的标签约束。单元格本身没有任何约束,但它确实将行高设置为 82 并在情节提要中自定义勾选

以上是关于动态单元高度自动布局 IOS的主要内容,如果未能解决你的问题,请参考以下文章

具有自动布局的 UITableView 中的动态单元格高度

具有自动布局的自定义单元格的动态高度

如何使用自动布局动态调整具有固定宽度的collectionview单元格高度?

滚动时 UITableViewCell 自动布局抖动的动态单元格高度问题

如何为具有动态高度的表格单元格正确设置自动布局?

基于动态标签高度的 iOS8 动态单元格高度