UITableView相关
1、基础知识
样式
UITableView有两种样式(plain,grouped),其中plain为普通列表样式,grouped是分组样式。可以在实例化的时候进行设置,默认是plain。
//tableview样式
let tableView = UITableView() //plain形式
let tableview = UITableView(frame:frame, style:.grouped) //grouped形式
tableview.separatorStyle = .singleLine //设置是否有横线,默认有横线
//tablecell样式
tablecell.selectionStyle = .gray //设置cell点击的样式,其中设置为none时候点击时候没有阴影效果
tablecell.accessoryType = .disclosureIndicator //设置cell尾部样式,箭头还是对号等等
数据源(UITableViewDataSource)
//行数(必须实现)
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
//每个cell(必须实现)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
//组数,非必须实现 默认是1
optional public func numberOfSections(in tableView: UITableView) -> Int
代理(UITableViewDelegate)
UITableViewDelegate继承UIScrollViewDelegate,也就是说UITableView其实拥有很多UIScrollView的操作。
//cell点击监听
optional public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
//取消点击后产生的阴影
optional public func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
//编辑操作,左滑
optional public func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
//cell即将展示
optional public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
2、问题集锦
1、取消TableView前后默认空白部分
- 代码示例
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0.01
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return nil
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.01
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return nil
}
- 注意事项
1.在设置 tableView.delegate = self 时注意将其放在tableView加入其View之前 ( ParentView.addSubview(tableView) ),否则上述代码不会生效。
2.在ios11系统以下,如果上述header以及footer置为0,则会认为其没有设置高度,还是会默认设置大约为50个像素的高度;ios11系统以上可直接设置为0;
2、TableView高度自适应
设置TableView高度自适应一般需要设置estimatedRowHeight以及rowHeight两个属性,并且cell的子控件布局要要实现自动布局(即cell的子控件需要将cell撑满)。其中estimatedRowHeight是一个对cell的预估高度,为其设置一个非负的预估高度可以提高表视图的性能,将一些几何计算的成本从加载时间推迟到滚动时间(预估高度和实际高度差值越小越好);rowHeight设为UITableView.automaticDimension;
//设置预估高度
tableView?.estimatedRowHeight = CGFloat((ContentHelp.approveItemContent.count + 1) * ConstantsHelp.itemRowHeight + ConstantsHelp.largePadding)
//设置高度自适应
tableView?.rowHeight = UITableView.automaticDimension
//cell自动布局代码
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tableCell:UITableViewCell = UITableViewCell(style: .default, reuseIdentifier: "cell")
tableCell.accessoryType = .disclosureIndicator
let itemUILabel = UILabel()
//设置换行
itemUILabel.lineBreakMode = .byWordWrapping
itemUILabel.numberOfLines = 0
tableCell.addSubview(itemUILabel)
itemUILabel.snp.makeConstraints { (make) in
make.top.left.right.bottom.equalTo(tableCell) //四个属性重要
}
return tableCell
}
3、TableView滚动条常在(具体原理百度上很多,ScrollView同理)
1、UIImageView扩展(oc代理类文件如何新建自行百度)
- .h文件(如果项目为swift工程,将该文件在桥接文件中声明以供swift使用)
#import <UIKit/UIKit.h>
#define noDisableVerticalScrollTag 836913 //竖向滚动
#define noDisableHorizontalScrollTag 836914 //横向滚动
NS_ASSUME_NONNULL_BEGIN
@interface UIImageView (ForScrollView)
@end
NS_ASSUME_NONNULL_END
- .m文件
#import "UIImageView+Scroll.h"
@implementation UIImageView (ForScrollView)
- (void)setAlpha:(CGFloat)alpha{
if (self.superview.tag == noDisableVerticalScrollTag) {
if (alpha == 0 && self.autoresizingMask == UIViewAutoresizingFlexibleLeftMargin) {
if (self.frame.size.width < 10 && self.frame.size.height > self.frame.size.width) {
UIScrollView *sc = (UIScrollView*)self.superview;
if (sc.frame.size.height < sc.contentSize.height) {
return;
}
}
}
}
if (self.superview.tag == noDisableHorizontalScrollTag) {
if (alpha == 0 && self.autoresizingMask == UIViewAutoresizingFlexibleTopMargin) {
if (self.frame.size.height < 10 && self.frame.size.height < self.frame.size.width) {
UIScrollView *sc = (UIScrollView*)self.superview;
if (sc.frame.size.width < sc.contentSize.width) {
return;
}
}
}
}
[super setAlpha:alpha];
}
@end
2、为tableView绑定标签
tableView.tag = Int(noDisableVerticalScrollTag)
以上代码可以实现tableView人工滚动后,滚动条显示后不会再消失。但刚进入不会直接显示滚动条,如果进入页面就直接显示滚动条,则需要添上以下代码;
3、进入页面直接显示滚动条
//当tableView绑定完数据后,使用flashScrollIndicators方法
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
tableView.flashScrollIndicators() //该方法会自动显示滚动条1~2秒,再配合1,2步骤代码就可以实现滚动条常在了。
}
4、提供一个获取tableView自适应高度的方法
近期开发中遇到了一个ScrollView嵌套tableView的场景,因为ScrollView需要依靠其子View的相对约束来计算其ContentSize,所以需要获取到tableView的高度。下面是相关代码。大致思路为在最后一个cell即将展示完毕之后,获取tableView的contentSize,此contentSize便为tableView的高度,将此值更新为tableView的高度约束。(可以提前给tableView设置一个平均高度,然后去更新这个约束,这样即使没有获取到实际高度,也不会有错误)
//在最后一个cell即将展示完毕之后,获取tableView的contentSize,此contentSize便为tableView的高度,将此值更新为tableView的高度约束
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if list.count > 0 , indexPath.row == list.count-1{
tableView.snp.updateConstraints{make in
make.height.equalTo(tableView.contentSize.height)
}
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
DispatchQueue.main.asyncAfter(deadline:.now()+0.5){
QL1(tableView.contentSize.height)
}
}
5、tableCell点击之后UIAlertController延迟弹出问题处理
猜测原因:点击事件触发后没有及时刷新UI,或者进入到了其他线程,主线程可能经过几次循环后之后才会发现UI变化,去刷新UI
//方法1
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false) //重点是 animated: false ,需要将是否显示动画设为false
}
//方法2,将弹出框操作放在主线程中进行
DispatchQueue.main.async {
//弹出框操作
}
//方法三
tableCell.selectionStyle = .none //不要将点击后颜色变化置为none
6、tablecell复用导致页面数据错位
可在使用复用的cell前,先删除cell之前的子view
let id = "cellId"
var tableCell = tableView.dequeueReusableCell(withIdentifier: id)
if tableCell == nil{
tableCell = UITableViewCell(style: .default, reuseIdentifier:id)
}else{
if (tableCell?.subviews.count)! > 0{
tableCell?.subviews.forEach{$0.removeFromSuperview()}
}
}