iOS-动态调整UITableViewCell的高度

2024-06-17 04:58

本文主要是介绍iOS-动态调整UITableViewCell的高度,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OS-动态调整UITableViewCell的高度iOS开发文档, by 友盟翻译组 stefaliu.

大概你第一眼看来,动态调整高度是一件不容易的事情,而且打算解决它的第一个想法往往是不正确的。在这篇文章中我将展示如何使图表单元格的高度能根据里面文本内容来动态改变,同时又不必子类化UITableViewCell。你当然可以通过子类化它来实现,但是这样做会使得代码复杂因为设置高度是在图表本身的实例上而不是对单元格操作。下面你将会看到这其实是一件轻而易举的事情。对于图表来说能够动态调整高度是件很有意义的事情,我首先想到的需要这个功能的是当显示一列长度会变化的文本列表时,如果文本内容较少,它或许能够适合正常的单元格label,但是如果文本变长,就不得不重新设置单元格大小以便于显示全部的文本内容。我总结了重新设置单元格大小的主要步骤如下:

1 创建并添加一个UILabel作为单元格cell的子视图;
2 在UITableView的委托方法: (CGFloat)tableView:(UITableView*)tableViewheightForRowAtIndexPath: (NSIndexPath *) indexPath中计算高度
3 在UITableView的委托方法: (UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath: (NSIndexPath *) indexPath中计算UILabel的框大小。

下面我要详细介绍这些步骤,首先看一下程序输出截图:

在普通的图表中,你可以简单地用下面的方法设置单元格内label的文本内容:

[[cell textLabel] setText:@"Text for the current cell here."];

也许你认为这样做就可以完全控制UILabel了,但是我发现我的任何要改变UILabel框大小的尝试都失败了,因此这并不是实现动态调整大小的一个好的候选方案。

我们需要设计一个UILabel然后把它添加到单元格的内容视图中。要实现它需要调用-cellForRowAtIndexPath,大致内容如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{UITableViewCell *cell;UILabel *label = nil;cell = [tv dequeueReusableCellWithIdentifier:@"Cell"];if (cell == nil){cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"] autorelease];label = [[UILabel alloc] initWithFrame:CGRectZero];[label setLineBreakMode:UILineBreakModeWordWrap];[label setMinimumFontSize:FONT_SIZE];[label setNumberOfLines:0];[label setFont:[UIFont systemFontOfSize:FONT_SIZE]];[label setTag:1];[[cell contentView] addSubview:label];}
}

这并不是完整的代码因为我们仅仅在创建单元格的时候初始化它的label,这段代码对应调用-dequeueReusableCellWithIdentifier之后的判断模块if(cell == nil)。
在这里我想强调两点:第一个,我们可以注意到label有一个标签与其对应,因为调用了-setTag:1。当cell不等于nil时这个标签可以用到。第二点,我们通过调用[[cell contentView] addSubview:label]来将label添加到单元格的内容视图中,这个只是在label初始化的时候用到。每调用这个函数都会添加label 到子视图序列中。下面我们会将这段代码补充完整,但之前先让我们看一下如何设置cell的高度。

计算cell的高度

在一个复杂的cell中,计算高度可能比较困难,但是你只需要关心那些高度会变化的部件就可以了。在我的例子中,唯一需要处理的就是添加到单元格中的label。我们根据文本的大小来计算cell 的高度,而文本的大小取决于文本的长度和文本字体。NSString类提供了函数-sizeWithFont来方便我们获取cell 的大小。下面的代码介绍了函数-heightForRowAtIndexPath:

1
2
3
4
5
6
7
8
9
10
11
12
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{NSString *text = [items objectAtIndex:[indexPath row]];CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];CGFloat height = MAX(size.height, 44.0f);return height + (CELL_CONTENT_MARGIN * 2);
}

你会注意到我们用到了几个常量来计算cell 的大小,它们的定义如下所示:

#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 320.0f
#define CELL_CONTENT_MARGIN 10.0f

常量CELL_CONTENT_WIDTH是整个cell的宽度。CELL_CONTENT_MARGIN是我们定义的页边空白,FONT_SIZE是我们采用文本的字体大小。

首先我们要创建一个内容宽度的约束条件。CGSizeMake的第一个参量是总共的内容宽度减去两个页边空白。因为左边和右边各有一个页边空白。第二个参数是我们提供的最大数值。这个约束条件在后面的函数-sizeWithFont中将会用到。在-sizeWithFont中我们设置为 UILineBreakModeWordWrap来获取在允许自动换行的情况和上面提到的约束条件下正确的大小。最后我们使用MAX宏设置cell的高度,并且保证cell 的高度不会小于44个像素,因为它返回size.height和44两个数中的最大值。最后,我们将上下的页边空白考虑进去得到最后的结果。

为了使得读者形象化的了解页边空白,下面一个截图可以看出有一个边界环绕着label。调用[[label layer] setBorderWidth:2.0f]可以显示该边界从而方便我们看到页边空白。

计算并设置UILabel框大小

在前面我们用来计算高度的方法也是我们用来设置UILabel框大小的方法。下面将-cellForRowAtIndexPath代码补充完整:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{UITableViewCell *cell;UILabel *label = nil;cell = [tv dequeueReusableCellWithIdentifier:@"Cell"];if (cell == nil){cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"] autorelease];label = [[UILabel alloc] initWithFrame:CGRectZero];[label setLineBreakMode:UILineBreakModeWordWrap];[label setMinimumFontSize:FONT_SIZE];[label setNumberOfLines:0];[label setFont:[UIFont systemFontOfSize:FONT_SIZE]];[label setTag:1];[[label layer] setBorderWidth:2.0f];[[cell contentView] addSubview:label];}NSString *text = [items objectAtIndex:[indexPath row]];CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];if (!label)label = (UILabel*)[cell viewWithTag:1];[label setText:text];[label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];return cell;
}

要注意if(cell == nil)模块是初始化代码,只在cell创建的时候运行一次。该模块外部代码每次都会执行只要在每次数据更新或者窗口拖拽之后调用了-cellForRowAtIndexPath

也就是说,每次都需要设置label中文本内容以及设置label外框大小。注意如果label处于未初始化状态,我们需要通过调用[cell viewWithTag:1]来获取UILabel的句柄。这段代码跟前面计算高度的代码基本相同。

总结

动态计算单元格cell的高度真的并不困难。如果你有一个很复杂的cell,你只需要根据内容宽度和特定文本字体的大小来确定cell的高度。如果你不清楚你的外框显示在什么地方,只需要通过调用[[view layer] setBorderWidth:2.0f]来使外框显示即可。这会有助于你了解绘图过程以及更快地在更深的层次理解绘图显示的问题。

演示工程文件:DynamicHeights Demo Project

作者:Matt Long
原文链接:http://www.cimgf.com/2009/09/23/uitableviewcell-dynamic-height/

这篇关于iOS-动态调整UITableViewCell的高度的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1068533

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

java获取图片的大小、宽度、高度方式

《java获取图片的大小、宽度、高度方式》文章介绍了如何将File对象转换为MultipartFile对象的过程,并分享了个人经验,希望能为读者提供参考... 目China编程录Java获取图片的大小、宽度、高度File对象(该对象里面是图片)MultipartFile对象(该对象里面是图片)总结java获取图片

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

Java导出Excel动态表头的示例详解

《Java导出Excel动态表头的示例详解》这篇文章主要为大家详细介绍了Java导出Excel动态表头的相关知识,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录前言一、效果展示二、代码实现1.固定头实体类2.动态头实现3.导出动态头前言本文只记录大致思路以及做法,代码不进

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字