博客> 简洁高效的Table控件正式版,适合复杂样式的内容排版
简洁高效的Table控件正式版,适合复杂样式的内容排版
1小时前 评论:0 阅读:29 skyMaster123
ios tableview swift objc 苹果 pull-to-refresh

简洁高效的Table控件1.1.0正式版,适合复杂样式的内容排版,丰富的元素相关API

AG亚游集团,  根据区域经济学的原理Communic Asia 2005、Nokia Connection 2005、索爱2005夏季新品发布会都是“泛新加坡通信展”的组成部分,在这个更大的范围内,还有更多东西值得我们关注。

  那次事件也是发生在美国太平洋舰队司令访问中国期间,这似乎是北京的一种谈判策略。怎么白手起家  所以我们就讲,是一个以人为本的搜索引擎,爱问是6月30号在新浪推出来的,我们经历了大概两年的研发过程,我们不简单地是在做程序,不简单地是在做页面,更主要的是用一个最基本的灵魂,就是以人为本的概念,把我们所有的努力,把我们所有的智慧结合在一起做这个搜索引擎。大家其实可以看到,接下来一个简单的演示,这是爱问的几个入口,大家可以看到在我们的网页正问页面右上角都有爱问的入口,在的中间当出现一个关键词的时候,也可以得到爱问。这就是我刚才谈到的叫爱问知识人,直接输入一个,比如口腔溃疡如何好得快,一个非常趋近于正常语言的问题,我们查找一下适合自己的答案,在这个答案当中,回答问题的人,分析了很多的方法,可以用各种各样的偏方来治口腔溃疡,在整个爱问知识人结构当中,我们设计了大量不同的题材和分类,大家的基本问题基本可以找到自己的分类得到解决。这是模拟一个人来问问题。把会员名字和密码输入进去。

之前做项目一直使用自己封装的Table控件,最近把他整理了下(不要脸的)开放出来。如果您用的比较爽的话请点击右上角的star关注下,也可以随时发送issues吐槽给我,我会随时发现并解决。 项目仓库地址

技术特点

  • 无需继承自定义类,引入头文件UIViewController+GYTableView.h即可使用
  • 支持OC和Swift(混合)
  • Section和Cell层次更加清晰,根据传入的Section数据结构内部已经全部实现Section和Cell相关delegate方法
  • Cell实例可获得外部动态数据,索引位置,上下关系,选中状态等,随时更换样式
  • 自带MJRefresh框架,提供下拉刷新和上拉加载功能
  • 提供Section,Cell间距设置,提供选中行高亮、选中行自动居中,提供设置Cell动态高度设置等API
  • 框架中的元素全部继承于原生的tableView,除部分代理方法外,其他原生方法扔然可以使用

安装方法

  • pod安装: pod 'GYTableViewController'
  • 手动安装:手动安装需要添加两个库,将GYTableViewController项目文件中Framework文件下的文件导入自身项目,同时此框架基于MJRefresh,所以也需要导入MJRefresh框架文件,手动或者pod都可以,MJRefresh安装方法请戳
  • demo项目图标基于iconfont技术栈,AG亚游集团请戳这里

框架用法

请使用该框架中的元素来代替原生Table控件,对应关系如下:

UIViewController+GYTableView -> UIViewController
GYTableBaseView -> UITableView
GYTableViewCell -> UITableViewCell
GYTableViewSection 原生使用UIView展示section内容,这里使用GYTableViewSection
SectionNode 用来设置Section样式与GYTableViewSection实例绑定
CellNode 用来设置Cell样式与GYTableViewCell实例绑定

使用时有Table控件的界面直接引入头文件UIViewController+GYTableView.h即可,.h示例如下 Objective-C

#import "UIViewController+GYTableView.h"
@interface YourViewController : UIViewController

swift项目在Bridging_Header桥接文件中引入UIViewController+GYTableView.h,参照demo示例

.m或swift实现文件必须开启gy_useTableView开关来使用Table控件GYTableView Objective-C

- (BOOL)gy_useTableView {
    return YES;
}

Swift

override func gy_useTableView() -> Bool {
    return true
}

.m或swift文件中重写headerRefresh添加元素,当自带的下拉刷新控件下拉时调用;从而开始Table内容层次搭建,以及各种类型的Cell位置如何摆放等

- (void)headerRefresh:(GYTableBaseView *)tableView {
 ? ?/下拉刷新后开始请求后台提供数据,请求到数据后根据解析的内容展开cell实例和位置等操作,代码结构如下(伪代码)
    request {
        tableView {
            sectionNode {
                cellNode,
                cellNode,
                ...
            }
            sectionNode {
                cellNode,
                ...
            }
            ...
        }
        [tableView headerEndRefresh:YES];/界面搭建完毕后停止刷新
    }
}

Cell控件直接继承GYTableViewCell,.h示例如下 Objective-C

#import "GYTableViewCell.h"
@interface YourViewCell : GYTableViewCell

Swift

class YourViewCell: GYTableViewCell

.m文件中重写showSubviews方法进行布局,利用getCellData获取Table控件中传入的数据 Objective-C

- (void)showSubviews {
    id yourData = [self getCellData];/先获取外部传入的数据
    /开始界面布局...
}

Swift

override func showSubviews() {
    let yourData = self.getData()
    /开始界面布局...
}

添加Cell

Table控制器内部实现

Objective-C

- (void)headerRefresh:(GYTableBaseView *)tableView {
    [tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
        /添加一个高度为230,类型为BannerViewCell,展示banner图片序列的Cell
        [sNode addCellNode:[CellNode initWithParams:230 cellClass:RefreshBannerViewCell.class cellData:Mock.bannerUrlGroup]];
    }]];
    [tableView headerEndRefresh:YES];/不要忘了结束刷新,否则刷新动画会停留原地
}

Swift

override func headerRefresh(_ tableView: GYTableBaseView!) {
    tableView.add(SectionNode.initWithParams({ sNode in
        /添加一个高度为230,类型为BannerViewCell,展示banner图片序列的Cell
        sNode?.add(CellNode.initWithParams(230, cellClass: RefreshBannerViewCell.self, cellData: Mock.bannerUrlGroup))
    }))
    tableView.headerEndRefresh(true)
}

案例1-1

批量添加Cell

Table控制器内部实现(暴力添加,Swift略过...)

- (void)headerRefresh:(GYTableBaseView *)tableView {
    [tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
        /添加一个高度为230,类型为BannerViewCell,展示banner图片序列的Cell
        [sNode addCellNode:[CellNode initWithParams:230 cellClass:RefreshBannerViewCell.class cellData:self.bannerUrlGroup]];
    }]];
    /注意banner和基金产品列表属于不同区域,应存放到各自section中添加,管理section视图会比较方便
    [tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
        /添加多个高度为80,类型为RefreshFundViewCell,展示基金信息的Cell
        [sNode addCellNode:[CellNode initWithParams:80 cellClass:RefreshFundViewCell.class cellData:self.fundModels[0]]];
        [sNode addCellNode:[CellNode initWithParams:80 cellClass:RefreshFundViewCell.class cellData:self.fundModels[1]]];
        [sNode addCellNode:[CellNode initWithParams:80 cellClass:RefreshFundViewCell.class cellData:self.fundModels[2]]];
        /...
    }]];
    tableView.headerEndRefresh(true);/不要忘了结束刷新,否则刷新动画会停留原地
}

相同类型的Cell添加可以修改成通过原数组批量添加

Objective-C

[tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
    /添加多个高度为80,类型为RefreshFundViewCell,展示基金信息的Cell
    [sNode addCellNodeByList:[CellNode dividingCellNodeBySourceArray:80 cellClass:RefreshFundViewCell.class sourceArray:Mock.fundModels]];
}]];

Swift

tableView.add(SectionNode.initWithParams({ sNode in
    sNode?.addCellNode(byList: CellNode.dividingCellNode(bySourceArray: 80, cellClass: RefreshFundViewCell.self, sourceArray: Mock.fundNewModels))
}))

案例1-2

添加Section

如果一节内容需要添加section页眉视图,只要在sectionNode实例设置sectionHeaderClass即可,同理section页脚设置sectionFooterClass

Objective-C

- (void)headerRefresh:(GYTableBaseView *)tableView {
    [tableView addSectionNode:[SectionNode initWithParams:36 sectionHeaderClass:RefreshFundViewSection.class sectionHeaderData:@"精品专区" nextBlock:^(SectionNode *sNode) {
        /添加section内的cell...
    }]];
    [tableView headerEndRefresh:YES];
}

Swift

override func headerRefresh(_ tableView: GYTableBaseView!) {
    tableView.add(SectionNode.initWithParams(36, sectionHeaderClass: RefreshFundViewSection.self, sectionHeaderData: "精品专区", nextBlock: { sNode in
        /添加section内的cell...
    }))
}

分类结构如下

静态图
案例1-3

isUnique唯一性

默认所有相同Class的Cell实例都是相互复用,每次下拉刷新或者table设置reloadData,被复用的Cell实例都会重新触发刷新调用showSubviews,从而根据传递的data展开;然而,一些特殊的Cell不需要复用或只实例化一次,比如标签按钮区域的Cell或者banner区域的Cell,每次下拉都是只用这个实例,可以设置为isUnique作为唯一Cell实例优化提高性能 Objective-C

- (void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler {
    [tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
       /添加一个高度为230,类型为BannerViewCell,展示banner图片序列的Cell
        [sNode addCellNode:[CellNode initWithParams:230 cellClass:RefreshBannerViewCell.class cellData:self.bannerUrlGroup isUnique:YES]];
        /添加一个高度为90,类型为RefreshHotViewCell,展示banner图片序列的Cell
        [sNode addCellNode:[CellNode initWithParams:90 cellClass:RefreshHotViewCell.class cellData:self.hotModels isUnique:YES]];
    }]];
    [tableView headerEndRefresh:YES];
}

Swift

override func headerRefresh(_ tableView: GYTableBaseView!) {
    tableView.add(SectionNode.initWithParams({ sNode in
        /添加一个高度为230,类型为BannerViewCell,展示banner图片序列的Cell
        sNode?.add(CellNode.initWithParams(230, cellClass: RefreshBannerViewCell.self, cellData: Mock.bannerUrlGroup, isUnique:true))
        /添加一个高度为90,类型为RefreshHotViewCell,展示标签按钮区域的Cell
        sNode?.add(CellNode.initWithParams(90, cellClass: RefreshHotViewCell.self, cellData:Mock.hotModels , isUnique:true))
    }))
    tableView.headerEndRefresh(true)
}

上拉加载更多

Table控制器内部设置显示上拉加载控制器

Objective-C

- (BOOL)gy_useLoadMoreFooter {
    return YES;
}

Swift

override func gy_useLoadMoreFooter() -> Bool {
    return true
}

Table控制器内部重写footerLoadMore

Objective-C

/lastSectionNode:上一节sectionNode数据,即当前Table页最后一节
- (void)footerLoadMore:(GYTableBaseView *)tableView lastSectionNode:(Section *)lastSectionNode {
    [lastSectionNode addCellNodeByList:[CellNode dividingCellNodeBySourceArray:80 cellClass:RefreshFundViewCell.class sourceArray:self.fundNewModels]];/将新增的CellNode实例继续添加到上一节SectionNode实例中
    [tableView footerEndLoadMore:YES];/不要忘了结束上拉加载刷新
}

Swift

override func footerLoadMore(_ tableView: GYTableBaseView!, last lastSectionNode: SectionNode!) {
    lastSectionNode.addCellNode(byList: CellNode.dividingCellNode(bySourceArray: 80, cellClass: RefreshFundViewCell.self, sourceArray: Mock.fundNewModels))/将新增的CellNode实例继续添加到上一节SectionNode实例中
    tableView.footerEndLoadMore(true)/不要忘了结束上拉加载刷新
}

根据需求添加到Table页最后一节,或者添加到新的一节数据中,并设置添加上限,业务相关代码swift示例略...

if ([tableView getTotalCellNodeCount] > 30) {/总共超出30条数据不添加数据
    [tableView footerEndLoadMore:NO];/直接结束上拉加载刷新,并显示"已经全部加载完毕"
    return;
}
/根据业务需求的不同,可以继续添加到上一节sectionNode,也可以添加到新的一节sectionNode中
if ([lastSectionNode getCellNodeCount] < 15 name="更改ui-tableView的frame"></a>
# 更改UITableView的frame
### Table控制器内部重写getTableViewFrame
如存在和容器底部对齐的元素,请在此方法对齐底部位置(默认占满controller边界);autoLayerout无需重写此方法,自行设置tableView和其他元素布局关系
Objective-C
```objc
- (CGRect)gy_getTableViewFrame {
    self.noticeBack.frame = CGRectMake(0, 0, self.view.width, 30);
    self.submitButton.maxY = self.view.height;/底部按钮对齐容器底部
    /返回设置好的tableView位置frame 高度=总高度-公告区高-底部按钮高
    return CGRectMake(0, self.noticeBack.height, self.view.width, self.view.height - self.noticeBack.height - self.submitButton.height);
}

Swift

override func gy_getTableViewFrame() -> CGRect {
    /...业务代码同上
    /返回设置好的tableView位置frame 高度=总高度-公告区高-底部按钮高
    return CGRect.init(x: 0, y: self.noticeBack.height, width: self.view.width, height:  self.view.height - self.noticeBack.height - self.submitButton.height);
}

案例2-1

自定义下拉刷新控件

Table控制器内部重写gy_getRefreshHeader

Objective-C

- (MJRefreshHeader *)gy_getRefreshHeader {
    return [[DiyRotateRefreshHeader alloc] init];
}

Swift

override func gy_getRefreshHeader() -> MJRefreshHeader! {
    return DiyRotateRefreshHeader()
}

案例2-2

侦听选中的Cell

Table控制器内部实现代理 (tableView:didSelectRowAtIndexPath:已废弃)

Objective-C

- (void)didSelectRow:(GYTableBaseView *)tableView indexPath:(NSIndexPath *)indexPath {
    CellNode* cNode = [tableView getCellNodeByIndexPath:indexPath];/获取到绑定的CellNode
    YourClass* yourData = cNode.cellData;/获得cell的原始数据
    /根据数据添加业务逻辑...
}

Swift

override func didSelectRow(_ tableView: GYTableBaseView!, indexPath: IndexPath!) {
    let cNode:CellNode? = tableView.getCellNode(by: indexPath)
    let yourData:YourClass? = cNode?.cellData as? YourClass
    /根据数据添加业务逻辑...
}

设置cell点击效果,cell实例内部重写showSelectionStyle

Objective-C

- (BOOL)showSelectionStyle {
    return YES;
}

Swift

override func showSelectionStyle() -> Bool {
    return true
}

案例2-3

设置Cell或Section元素间距

Table控制器内部设置tableView属性cellGap或sectionGap

Objective-C

- (void)viewDidLoad {
    self.tableView.sectionGap = 6;/设置每一节区域之间间距
    self.tableView.cellGap = 3;/设置每个Cell之间间距(包含每一节区域)
}

Swift

override func viewDidLoad() {
    self.tableView.sectionGap = 6/设置每一节区域之间间距
    self.tableView.cellGap = 3/设置每个Cell之间间距(包含每一节区域)
}

案例3-1

设置选中某个位置的Cell

当刷新完成后设置,Table控制器内部设置tableView属性selectedIndexPath

Objective-C

- (void)headerRefresh:(GYTableBaseView *)tableView {
     [tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
        /..添加cell数据
     }]];
     tableView.selectedIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];/设置选中某个indexPath
     [tableView headerEndRefresh:YES];
}

Swift

override func headerRefresh(_ tableView: GYTableBaseView!) {
    tableView.add(SectionNode.initWithParams({ sNode in
        /..添加cell数据
    }))
    tableView.selectedIndexPath = IndexPath.init(item: 0, section: 0)
    tableView.headerEndRefresh(true)
}

Cell实例设置选中效果,重写setSelected方法,选中样式请根据需求自行添加

Objective-C

- (void)setSelected:(BOOL)selected {
    [super setSelected:selected];
    [self checkCellRelate];/自定义选中样式方法,非框架内部方法,实现如下
}

Swift

override var isSelected:Bool {
    set {
        super.isSelected = newValue
        self.checkCellRelate()/自定义选中样式方法,非框架内部方法,业务实现略过...
    }
    get{
        return super.isSelected
    }
}

Cell实例位置关系isFirst,isLast,位于第一个或最后一个和中间段的Cell样式不同

- (void)checkCellRelate {
    if (self.isFirst) {
        [self drawFirstStyle:nodeColor];
    }else if(self.isLast){
        [self drawLastStyle:nodeColor];
    }else{
        [self drawNormalStyle:nodeColor];
    }
}

案例4-1

设置交互点击某个位置Cell并高亮

Objective-C

- (void)viewDidLoad {
    self.tableView.clickCellHighlight = YES;
}

Swift

override func viewDidLoad() {
    self.tableView.clickCellHighlight = true
}

案例4-2

设置点击Cell自动居中

Objective-C

- (void)viewDidLoad {
    self.tableView.clickCellMoveToCenter = YES;
}

Swift

override func viewDidLoad() {
    self.tableView.clickCellMoveToCenter = true
}

案例4-3

Cell自动调整高度

Table控制器内部设置CellNode传入高度CELL_AUTO_HEIGHT

Objective-C

- (void)headerRefresh:(GYTableBaseView *)tableView {
    [tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
        [sNode addCellNodeByList:[CellNode dividingCellNodeBySourceArray:CELL_AUTO_HEIGHT cellClass:AutoHeightWeiboCell.class sourceArray:Mock.weiboModels]];
    }]];
    [tableView headerEndRefresh:YES];
}

Swift

override func headerRefresh(_ tableView: GYTableBaseView!) {
    tableView.add(SectionNode.initWithParams({ sNode in
        sNode?.addCellNode(byList: CellNode.dividingCellNode(bySourceArray: CELL_AUTO_HEIGHT, cellClass: AutoHeightWeiboCell.self, sourceArray: Mock.weiboModels))
    tableView.headerEndRefresh(true)
}

Cell实例重写getCellHeight方法获取动态高度,获取高度内容会被缓存不会二次计算

Objective-C

- (CGFloat)getCellHeight:(CGFloat)cellWidth {
    WeiboModel *weiboModel = [self getCellData];/获取Model
    NSString *content = weiboModel.content;/获取动态内容字符串
    CGRect contentSize = [content boundingRectWithSize:CGSizeMake(cellWidth - LEFT_PADDING - RIGHT_PADDING, FLT_MAX)
    options:NSStringDrawingUsesLineFragmentOrigin
    attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:TVStyle.sizeTextSecondary]}
    context:nil];/计算给定范围内最佳尺寸
    return TOPIC_AREA_HEIGHT + contentSize.size.height + IMAGE_AREA_HEIGHT + BOTTOM_PADDING * 2;/返回计算后的最终高度
}

Swift

override func getHeight(_ cellWidth: CGFloat) -> CGFloat {
    let weiboModel:WeiboModel? = getData() as? WeiboModel/获取Model
    let content:String  = weiboModel!.content /获取动态内容字符串
    let contentSize:CGRect = content.boundingRect(with: CGSize.init(width: cellWidth - AutoHeightWeiboCell.LEFT_PADDING - AutoHeightWeiboCell.RIGHT_PADDING, height: CGFloat(Float.greatestFiniteMagnitude)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font:UIFont.systemFont(ofSize: TVStyle.sizeTextSecondary)], context: nil)
    /计算给定范围内最佳尺寸
    return AutoHeightWeiboCell.TOPIC_AREA_HEIGHT + contentSize.size.height + AutoHeightWeiboCell.IMAGE_AREA_HEIGHT + AutoHeightWeiboCell.BOTTOM_PADDING * 2;/返回计算后的最终高度
}

案例5-1

自定义创建TableView

无上拉加载和下拉刷新控件的干净TableView实例

Objective-C

self.tableView = [GYTableBaseView table:self];/创建并设置delegate
[self.tableView addSectionNode:[SectionNode initWithParams:^(SectionNode *sNode) {
    /添加元素...
}]];
[self.tableView gy_reloadData];/不要忘了刷新Table

Swift

self.tableView = GYTableBaseView.table(self);/创建并设置delegate
self.tableView?.add(SectionNode.initWithParams({ sNode in
    /添加元素...
}))
self.tableView?.gy_reloadData();/不要忘了刷新Table

ChangeLog

1.1.0 当前版本,框架结构整体修改,兼容swift混编,底层delegate优化为动态绑定

历史版本

1.0.0 初版
1.0.1 iOS11.0 Table自动上移bug修复
1.0.2 自定义上拉加载控件支持
1.0.3 增加autolayout支持,修改TableBaseView参数传入方式
1.0.6 添加UIViewController+GYTableView分类
1.0.7 delegate添加prepareCell用来自定义对cell进行操作
1.0.8 部分bug修复
收藏
0
sina weixin mail 回到顶部
拼车市场升温:印尼Go-Jek融资15亿美元 谷歌参投 26+11+5+3断!赛季最硬气1仗 火箭有他就打不死 汽车人的百年梦想:飞行汽车 德媒评述:美国批评中国贸易政策是在找“替罪羊” 全球债务总量创164万亿美元新高 中国增长占四分之三 男子42万首付被“偷”伤心欲绝 真相让人大跌眼镜 德警方:明斯特尔汽车撞人事件或系个人原因犯案 三峡集团拟百亿美元收购葡萄牙电力 最大障碍是美国 中国科学院院士欧阳自远:今年着陆月背没问题 中国5年日均脱贫3.7万人 印网友:印穷人越来越穷 国乒小将资格赛即输球 乒协新政是不是拔苗助长 这支中国防暴队多次获非洲一国国家奖 什么来头?
中国杯豪华阵容陆续浮出水面 3.15亿欧关键先生们来了 兴业投资:非美冲高回落 紧盯Fed主席鲍威尔首秀 灰色套现蔓延!“花呗白条套现”小广告盯上共享单车 Uber推出Uber Health:帮助患者出行 但不… 一方斗申花攻守抉择为难斯帅 大奎丰特同争一名额 托马斯是下一个雷曼? 或无法在赛场享受球王荣耀 [新浪彩票]30日竞彩异常指数:米竞技全身而退 2万家政府网首晒“年检”报告 98%网民留言及时办结 73能力值小将霸气隔扣威少!这下2K该换图了吧 东航董事长:民航空域仅20%多一点 建议合理配置 论文不好发薪资待遇低:芯片人才缺口40万 怎么补短板 美媒:这三个优势曾为美带来繁荣 如今一去不复返
北京队:杰克逊出战意愿强烈 医疗组确认他伤愈 全国政协委员:按搜查程序对扣查手机行为进行约束 新华网:宪法增监察委一节是监督制度重大顶层设计 红网评老人病危时称有17万私房钱:缘于老有所忧 美银美林:美国企业债今年会遭国外投资者抛弃 美国需求强劲+沙特力挺减产 美油三连阳收复64关口 武警工程大学原校长张锁明调任武警部队副参谋长 两大可乐巨头业绩猛跌 非碳酸业务转型乏力 菲向大陆遣返78名台籍诈骗嫌犯 台当局又“严正抗议” 白手起家好项目 一万元猪舍建设图片 过年摆地摊赚10万 今年开什么店好 AG亚游集团