IOS详解TableView——性能优化及手工绘制UITableViewCell

2023-05-16

提高表视图的性能

UITableView作为应用中最常用的视图,它的性能优化问题几乎是经常提及。下面对在非网络访问情况下的表视图性能优化进行了主要的几点说明:
1.自定义类或XIB文件时
在系统提供的样式不能满足我们的时候,我们经常会创建自定义类或者XIB文件来自定义单元格样式。
在之前,我们通常通过loadNib的方式或者在代理方法中继续使用老的方法来设置重用,管理缓存池。在IOS6以后,我们可以通过注册的方式在注册单元格甚至表头视图,让系统来更高效的进行管理。
2.InterfaceBuilder
据说有很多偏执的工程狮们坚持手打代码来完成工程,讨厌拖拖拽拽。不过随着IB的不断强大,已经有越来越多的人喜欢上了使用IB来建立和管理界面。在新的Xcode5中,IB又进步了不少。回到正题,尽管如此,在使用高性能的Cell时,还是推荐使用代码来创建单元格类。当UITableViewCell拥有多个子视图时,IOS的渲染机制会拖慢速度。重写drawRect直接绘制内容的方式可以提高性能,而不是在类初始化的时候初始化一些label或者imageview等。
3.图层颜色问题
透明图层对渲染性能会有一定的影响,系统必须将透明图层与下面的视图混合起来计算颜色,并绘制出来。减少透明图层并使用不透明的图层来替代它们,可以极大地提高渲染速度。
4.渲染中注意的问题
绘制时要尽可能的避免分配资源,比如UIFont,NSDateFormatter或者任何在绘制时需要的对象,推荐使用类层级的初始化方法中执行分配,并将其存储为静态变量。
5.为代理方法瘦身
我们经常能看到在项目中,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
这个方法中的代码多的吓人,我们可以讲一些数据绑定到cell中,或者在有多个tableview的时候,将其绑定到其他的tableviewcontroller中去。这样可以方便维护和管理,其实也对程序运行性能有很大的帮助。

手工绘制单元格

下面就绘制一个表视图单元格,并在表视图中显示。
初始化数据
- (void)loadAnimals
{
    _animalList = [NSMutableArray arrayWithCapacity:rAnimalCount];
    for (NSInteger i = 0; i < rAnimalCount; i++)
    {
        Animal *animal = [[Animal alloc] init];
        NSString *name = [NSString stringWithFormat:@"Animal-%03d", i+1];
        NSString *detail = [NSString stringWithFormat:@"dog or cat?"];
        NSInteger seed = arc4random()%8 + 1;
        NSString *imageName = [NSString stringWithFormat:@"head%02d", seed+1];
        
        animal.name = name;
        animal.detail = detail;
        animal.imageName = imageName;
        
        [_animalList addObject:animal];
    }
}

重点在于绘制,我首先创建了一个继承自UITableViewCell的父类一会让我们的单元格继承它,父类中有一个UIView类型的contentView成员,所有的绘制将在这个成员上进行。
@interface HRCellView : UIView
@end
@implementation HRCellView
- (void)drawRect:(CGRect)rect
{
    [(HRCell *)[self superview] drawContentView:rect];
}
@end

@implementation HRCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        contentView = [[HRCellView alloc] init];
        contentView.opaque = YES;   //不透明,提升渲染性能
        [self addSubview:contentView];
    }
    return self;
}

- (void)setFrame:(CGRect)frame
{
    [super setFrame:frame];
    CGRect b = [self bounds];
    b.size.height -= 1;     // 给分割线留出位置
    contentView.frame = b;  
}

- (void)setNeedsDisplay
{
    [super setNeedsDisplay];
    [contentView setNeedsDisplay];
}

- (void)drawContentView:(CGRect)rect
{
    //子类实现
}
@end


下面是绘制单元格
在初始化类方法中初始化字体资源
static UIFont *NameFont;
static UIFont *DetailFont;

@implementation HRCustomCell

+ (void)initialize
{
    NameFont = [UIFont fontWithName:@"American Typewriter" size:rNameFontSize];
    DetailFont = [UIFont fontWithName:@"American Typewriter" size:rDetailFontSize];
}

将数据绑定到这个单元格中
- (void)bindAnimal:(Animal *)animal
{
    if (_nameText != animal.name)
    {
        _nameText = animal.name;
    }
    if (_detailText != animal.detail)
    {
        _detailText = animal.detail;
    }
    if (_imageName != animal.imageName)
    {
        _imageName = animal.imageName;
    }
    
    [self setNeedsDisplay];
}


实现父类的drawContentView方法,实现绘制
- (void)drawContentView:(CGRect)rect
{
    static UIColor *nameColor;
    nameColor = [UIColor blackColor];
    static UIColor *detailColor;
    detailColor = [UIColor darkGrayColor];
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect cellRect = self.frame;
    
    if (self.highlighted || self.selected)  //选择或高亮时对应的颜色
    {
        CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
        CGContextFillRect(context, CGRectMake(0, 0, cellRect.size.width, cellRect.size.height));
    }
    else
    {
        CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
        CGContextFillRect(context, CGRectMake(0, 0, cellRect.size.width, cellRect.size.height));
    }
    
    UIImage *image = [UIImage imageNamed:_imageName];
    [image drawInRect:CGRectMake(5, 5, 50, 50)];
    
    [nameColor set];
    [_nameText drawAtPoint:CGPointMake(65, 10)
                  forWidth:200
                  withFont:NameFont
                  fontSize:rNameFontSize
             lineBreakMode:NSLineBreakByWordWrapping
        baselineAdjustment:UIBaselineAdjustmentAlignBaselines];
    
    [detailColor set];
    [_detailText drawAtPoint:CGPointMake(180, 40)
                    forWidth:120
                    withFont:DetailFont
                    fontSize:rDetailFontSize
               lineBreakMode:NSLineBreakByWordWrapping
          baselineAdjustment:UIBaselineAdjustmentAlignBaselines];
}

虽然方法很长,但是只要会简单的quartz绘图这些都是最基础的方法。
完成后我们讲这个类注册到tableview中
[self.tableView registerClass:[HRCustomCell class] forCellReuseIdentifier:CellIdentifier];
再来看我们的代理方法
就只有3行,比把数据都从这里赋值的方法要简洁许多。
完成的效果图
如果用真机调试,性能也要比使用非手工绘制的性能要好很多。
demo示例点击打开链接
以上为本篇博客全部内容,欢迎指正和交流。转载注明出处~
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IOS详解TableView——性能优化及手工绘制UITableViewCell 的相关文章

  • Gmail 中删除了 iOS 深层链接

    我正在尝试发送一封带有深层链接的电子邮件到我的 iOS 应用程序 使用 myapp 格式从电子邮件中将其打开 它可以在任何 iOS 邮件客户端 邮件 邮箱等 中运行 即点击它打开应用程序 但不能在 Gmail 应用程序 甚至网络 中运行 因
  • 如何让 iPhone 屏幕变暗

    我的 iPhone 屏幕上有一个刷新按钮 可以刷新当前视图中的表格 屏幕刷新得很漂亮 但是有没有办法让屏幕变暗 然后在表格刷新后再次变亮 您可以在要调暗的视图上放置一个带有黑色背景的非不透明视图 默认情况下 其 alpha 值为 0 因此是
  • 在 iPhone 上搜索 PDF

    经过两天尝试使用 Quartz 从 PDF 中读取注释后 我成功做到了并且发布我的代码 https stackoverflow com questions 4080373 get pdf hyperlinks on ios with qua
  • 在 iOS 中,如何以编程方式填写 pdf 表单字段?

    我需要获取一个现有的 pdf 文件 并以编程方式填写带有文本的表单字段列表 然后保存 pdf 而不将其显示给用户 例如 如果 pdf 文件包含名为 LastName 和 FirstName 的字段 我想将 FirstName 的值设置为 L
  • TestFlight Beta 中的消息不可用

    I am seeing Unavailable message in TestFLight Beta App in iOS8 Please find the attached screenshot please tell me how to
  • 自定义信息窗口上的按钮未接收 ios 中的操作

    我在 iOS 应用程序中使用 Google 地图 并实现了一个自定义信息窗口来显示标记的标题 现在 我在该自定义信息窗口上添加了一个按钮 但我的问题是按钮操作方法没有被调用 自定义信息窗口 h import
  • 如何将 Android 应用程序添加到已在 iOS 应用程序中使用的现有 Firebase 项目?

    我一直在我的 iOS 应用程序中使用 Firebase 项目 我现在想开始为 Android 应用程序使用相同的 Firebase 项目及其所有数据库和存储 在您的应用程序下Overview菜单 你应该按添加另一个应用程序并选择Androi
  • iOS 无法获取人物图像

    我有两个 tableViewController 第一个有联系人列表 另一张显示详细的人员信息 第一个tableViewController的一段代码 ABAddressBookRef addressBook ABAddressBookCr
  • Flutter-iOS 当应用程序更新/重新编译时存储的图像丢失

    嗨 请原谅我的英语 也是 flutter iOS 的新手 我在 iOS 上有一个关于 flutter 的应用程序 用户可以从他们的相机和图库中拍摄照片和视频 我正在使用 image picker 包 这没有问题 然后我将其保存在在其应用程序
  • 在 Pages 文稿中打开文本—Swift

    在我的 Swift 2 应用程序中 用户通过文本字段创建一串文本 然后将其共享给另一个应用程序 现在 我只能将文本共享为 txt 文件 这不提供选项Open In Pages当我打开系统共享对话框时 如何才能让用户可以选择将输入的文本作为
  • 在 iOS 7 中查看 Core Data 创建的 sqlite 文件时出现问题

    当我尝试访问由核心数据创建的数据库文件时遇到问题 DB 文件位于 Documents 文件夹中 我已将其复制到桌面并使用 Firefox 插件打开它 Hello sqlite文件不包含任何行我有使用核心数据插入值 我正在使用 iOS 7 模
  • 如何在导航栏上添加 UIView?

    我需要覆盖UINavigationBar with UIView像这儿 除了使用带有按钮返回的自定义 UIView 作为导航栏之外 还有其他方法可以做到这一点吗 您可以将子视图添加到应用程序的基本视图 UIApplication share
  • 从字典创建 Swift 对象

    如何根据 Swift 字典中的查找值动态实例化类型 希望这对其他人有用 我们需要进行一些研究才能弄清楚这一点 目标是避免巨大的 if 或 switch 语句从值创建每个对象类型的反模式 class NamedItem CustomStrin
  • Bootstrap 响应式表格在 iOS 设备上无法垂直滚动

    这就是我所拥有的 div class table responsive table class table style background transparent table div 我正在使用以下 bootstrap css 文件 ht
  • 依赖于不同队列上的另一个操作的 NSOperation 无法启动

    我有操作的依赖图 并且使用多个队列来组织各种操作流 例如 peopleQueue sitesQueue sessionQueue sessionQueue loginOp fetchUpdatedAccountOp peopleQueue
  • 如何将设备上未保存的图片上传到dropbox帐户?(IOS)

    Dropbox RestClient 仅保存文件 所以我想先将图像保存在本地文件夹中 然后上传它 结果它保存了文件 但它已损坏 NSString localPath NSBundle mainBundle pathForResource I
  • 如何从第二个视图弹回到根视图?

    我使用 2 将 3 个视图 根视图 第 1 个视图 第 2 个视图 连接在一起modal在 Apple Watch 故事板中继续 1 在根视图中 按下 保存 按钮后 将显示第一个模态视图 2 在第一模态视图中 一旦按下 500 按钮 将显示
  • 获取所有ios应用程序的全局列表[重复]

    这个问题在这里已经有答案了 我想对苹果应用商店进行一些全球统计 一个瓶颈是至少获取所有当前活动应用程序的 ID 这 9 位数字 有谁知道如何获取 iOS 应用商店中当前活动应用程序的所有 id 的完整列表 更好的是特定类别的所有 ID 例如
  • 如何制作像 Facebook 应用程序一样的登录屏幕?

    如何制作像 Facebook 应用程序一样带有 电子邮件 和 密码 文本字段的登录屏幕 Facebook登入 http extdesenv com wp content uploads 2012 05 facebook login ios
  • TestFlight 安装的应用程序因 Swift 包管理器依赖项而崩溃

    我们已经迁移了一些 CocoaPod 依赖项 以便在 Xcode 11 中使用 Swift Package Manager 进行构建和链接 但是 每当我们将应用程序提交到 AppStore Connect 并使用 TestFlight 进行

随机推荐