重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要讲解了“如何使用UITableView”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用UITableView”吧!
成都创新互联制作网站网页找三站合一网站制作公司,专注于网页设计,成都网站制作、网站建设、外贸网站建设,网站设计,企业网站搭建,网站开发,建网站业务,680元做网站,已为上1000家服务,成都创新互联网站建设将一如既往的为我们的客户提供最优质的网站建设、网络营销推广服务!
在我们iOS开发中UITableView
几乎是所有App都会使用的一个UI控件,因为业务的需要,我们常常会注册多种Cell,然后在
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
中就会很自然的写出一堆类似这样的代码:
事件处理的代码大概是这样的:
这似乎没有什么问题,代码很干净,逻辑也比较清晰。
但是你维护几个版本之后,或者遇到了一个善变的产品经理。
你会发现,这样的代码维护起来真的很危险,稍微一不注意就出错了,这里用的type
作为判断条件可能相较与indexPath
要好一点。
如果使用indexPath
作为判断条件,如果你的cell顺序有变化,或者有改动,那么你可能至少需要维护以下几个地方:
你的模型数组
cell dequeue的判断条件
事件处理的判断条件
。。。。
维护的东西越多,意味着你出错的概率是越大的。
那有没有什么好的方法处理这类代码?
其实我们仔细想想,无论一个多么复杂的UITableView
,与之对应的其实只要一个模型数组。
那么我们如果维护好了模型数组,是不是就维护好了UITableView
中所有的cell,这是显而易见的。
如果我们的UITableView
中有N种cell样式,那么模型数组中肯定也会有N种模型。
也就是说每种cell与每种模型是一一配对的,常规的模型与cell绑定是如上述的思路。
上述的思路,显然不是我们想要的,维护起来太不便,而且耦合性也比较大。
想一想展示一个UITableView
的过程
发起网络请求
JSON to Model,构造模型数组
数据填充
大致就是这三步吧。
其实在第二步构造模型数组时,我们是不是就可以确定好UI的样式了?
如果这里想不明白,再看看我们上面的分析,一种cell样式对应着一种模型,那么我们知道了模型,是不是就知道了cell样式
如果你还是不大清楚,那们就进入实战部分
先看这样一个简单的页面,你肯定会说:朋友,你TM在逗我们,这和UITableView
有毛关系?
这个界面需要UITableView
?
没错,这个界面在UIViewController
中直接构建就可以了。
是不是感觉都很类似,但是又有很多不同的地方。
一个一个VC的写。
缺点:
有很多重复代码,而且后期的改动需要维护的地方,做不到高内聚。
抽象一个父类
缺点:
虽然三个VC看似UI上有很多共同之处,但是其中的业务处理完全不同的
抽象一个UIHelper用于构建UI
缺点:
这种方案看似很好了,但是你看如果在一个界面中,如果添加一个或者减少一个控件,又得重新做约束了,这也显然不是我们想要的。
下面看看通过UITableView
构建的UI
SignInVC 中的代码:
PasswordSignVC 中的代码:
再看cell的dequeue代码
数据的绑定,全部分散到了每个cell中。
Row.h的代码
#importNS_ASSUME_NONNULL_BEGIN@protocol Updatable @optional- (void)updateViewData:(id)viewData;@end@interface Row : NSObject@property(nonatomic, copy, readonly) NSString *reuseIdentifier;@property(nonatomic, strong, readonly) Class cellClass;@property(nonatomic, strong, readonly) id model;- (instancetype)initWithClass:(Class)cls model:(id)model;- (instancetype)initWithClass:(Class)cls;- (void)updateCell:(UITableViewCell *)cell;@enDNS_ASSUME_NONNULL_END
Row.m的代码
@interface Row()@property(nonatomic, strong, readwrite) Class cellClass;@property(nonatomic, strong, readwrite) id model;@end@implementation Row- (instancetype)initWithClass:(Class)cls { if (self = [self initWithClass:cls model:@""]) { } return self;}- (instancetype)initWithClass:(Class)cls model:(id)model { if (self = [super init]) { self.cellClass = cls; self.model = model; } return self;}- (void)updateCell:(UITableViewCell *)cell { if ([cell respondsToSelector:@selector(updateViewData:)]) { [cell performSelector:@selector(updateViewData:) withObject:self.model]; }}- (NSString *)reuseIdentifier { return [NSString stringWithFormat:@"%@", self.cellClass];}@end
整个Row的代码不过100行,把所有的处理都内聚在了一起,我们只要维护好模型数组就能很好的管理UITableView
Cell 高度计算
Cell上事件的回调
在iOS8之后UITableView
中推出了Self-sizing的功能,所以Cell的高度改变
UIView *dummyView = [[UIView alloc] init]; dummyView.translatesAutoresizingMaskIntoConstraints = NO; [self.contentView insertSubview:dummyView belowSubview:self.textField]; [dummyView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor].active = YES; [dummyView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor].active = YES; NSLayoutConstraint *constraint = [dummyView.heightAnchor constraintEqualToConstant:60]; constraint.priority = 999; constraint.active = YES;
如果你对这块不熟悉,请 跳转。如果你想对Auto Layout有一个提高建议看看 Auto Layout Guide, 如果你想知道
systemLayoutSizeFittingSize
的作用,请看 深入理解Auto Layout 第一弹
有人肯定会不屑这里,但是我想说:如果不用block、代理、观察者。
怎么把cell上button的事件回调到VC中(button没有暴露给外部)?
我们先看添加Action的方法
- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
这里需要这三个参数:
target(action的相应者)
action(点击按钮相应的方法)
controlEvents(这个一般为UIControlEventTouchUpInside)
只要我们找到了target,把action写到target里这个action绑定是不是就完成了。
target其实就是我们的VC,我们只要把VC传递给Cell即可,但是这样是不是Cell又和VC耦合了啊。这个用block,delegate没什么区别吧!
现在我们需要解决的问题就是找到Cell的VC,大功即可告成。
这是就需要一个重要的概念闪亮登场iOS 响应链(Responder Chain)
这里就不展开了,但是你一定要去了解这个。
响应链可以解决的问题:
扩大相应区域
超出父类视图相应依然可以传递
垮图层传递事件
找到UIView
的UIViewController
- (UIViewController *)viewController { UIResponder *responder = self; while (![responder isKindOfClass:[UIViewController class]]) { responder = [responder nextResponder]; if (nil == responder) { break; } } return (UIViewController *)responder;}
ButtonCell事件绑定代码:
这里我们还是要用一个协议的:
用这个协议主要是方便代码的阅读,而且在Swift中是必须使用协议的,因为编译时找不到这个方法。
可以看到ButtonCell的代码中并没有这样一段代码
@property (nonatomic, weak) iddelegate;
或者
@property (nonatomic, strong) void (^buttonAction)(void);
这样我们的ButtonCell不会和VC耦合,修改起来真的很方便
感谢各位的阅读,以上就是“如何使用UITableView”的内容了,经过本文的学习后,相信大家对如何使用UITableView这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!