说起tableView,大家都不陌生,但是说起tableView的section和row,对其概念总是很模糊,什么不要线、设置线宽度、sectionHeader高度等等,有时还真得花一些时间去调试,总的说来,还是对tableView这些细节不太熟悉,下面我总结了一些小细节,希望对大家有所帮助
1一个section:两个cell之间的行间距无法改变
2多个section:能改变两个相邻section的相邻cell之间的高度,即区头和区尾高度
3cell默认是整个tableView都有分隔线的,即系统默认属性是
所以要想去掉分隔线,一般是
但是此时你会发现有内容的cell分隔线也没了,对于有内容的cell,我们一般是保留其分隔线的,不用急,往下看
4上面说了,系统默认是
如果我们不手动去调用separatorStyle这个属性,cell之间是有线的,这时可以设置heightForFooterInSection和heightForHeaderInSection,值得注意的是,如果最底部区尾高度设置为0,下面无内容的cell的分隔线是去不掉的,所以只要给区尾设置一个高度即可去掉分隔线,同时保留有内容的cell的分隔线,至于区头和区尾设置多高根据需求而定
5多个section有多个区头和区尾,如果设置区头过高,当你往上滑动时,区头也会往上移动,但是如果达到了tableView顶端,会发现第一个区头会停留在顶端,不再随cell移动而往上移动,但是你再往下拉,会随tableView滑动而下来,如果在自定义headerView时,如果想要这种效果,完全可以这么做
6不设置相邻区头和区尾高度或者设置为0,在UITableViewCellSeparatorStyleSingleLine情况下,两个section之间的高度默认是分割线的高度
7设置cell分隔线的宽度
宽度为0:
屏幕宽度:
小贴士:没有数据时,记得去掉分隔线哦,不然会有可能会有一条线在上面
1系统默认UITableViewCellSeparatorStyleSingleLine,但不会出现多余的分隔线
2如果不设置区头和区尾高度,或者设置为0,区头和区尾均为默认高度,大概为15
3区头或者区尾高度设置成很小貌似不行,比如0001,运行出来的效果还是差不多1的高度
4区头和区尾会一直随着tableView滚动,不会停留在顶部或底部
在有规律的列表中,我们可以有四种选择布局,假如数据源数组为array
1plain:返回section数为arraycount 每组一个row 可以精确的改变两个cell之间的高度 但是区头会停留在顶部,需要做判断解决第一个区头高度问题
2plain:返回section数为1 共arraycount个row 无法改变两个cell之间的高度
3grouped:返回section数为arraycount 每组一个row 即使区头和区尾之间高度给的再小,高度依然接近于1
4grouped:返回section数为1 共arraycount个row 无法改变两个cell之间的高度
具体哪种按需求去选择
复杂的tableView也可以借鉴上面四种去选择
1 webView加载H5链接,设置它为tableView的 headerView,下方评论信息用Cell加载展示。
2 在webView的回调方法webViewDidFinishLoad中获取网页内容高度,设置为webView的高度,重新将webView赋给tableView的headerView。
Tip: 将一个View赋值给UITableView的tableHeaderView时,不需要手动设置高度,HeaderView会自动使用View的高度。
像上面这样,类似的方法很多,无论是JS获取,还是contentSize获取,最后结果都难以获取到准确高度,并非方法不行,而是:
技术点:UILabel的自动换行,自动换行的同时要自适应Frame大小。UITableView的行高自适应内容,实时调整高度。实现方法:UILabel的自动换行获取UILabel的frame大小获取UILabel的字体大小获取UILabel的文本内容根据上面的3部分数据,计算文本显示区域大小根据4计算的大小,实时改变UILabel的framecode如下:NSStringlabelStr=@“你好,这是UILabel的自动换行测试内容,主要实现多行数据的自动换行,自适应不同行数的数据”;CGSizelabelSize={0,0};labelSize=[labelStrsizeWithFont:[UIFontsystemFontOfSize:14]constrainedToSize:CGSizeMake(2000,5000)lineBreakMode:UILineBreakModeWordWrap];//14为UILabel的字体大小//200为UILabel的宽度,5000是预设的一个高度,表示在这个范围内
在IOS开发中,很多时候项目需求会有点击某一行,展开cell下面的cell,在此点击会收起;
这种实现方式很多,个人这里随便推荐一种实现方式:
1、在数据转模型的model里面添加一个属性, @property ( assign , nonatomic ) BOOL isOpen; //是否展开
2、在对应的tableView层,- ( nullable UIView)tableView:(UITableView)tableView viewForHeaderInSection:(NSInteger)section;方法下面生成View,并未其添加点击事件;点击事件方法如下:
在对应的tableView的dataSource方法中:
以及- (UITableViewCell)tableView:(UITableView)tableView cellForRowAtIndexPath:(NSIndexPath)indexPath{ if ( self dataList[indexPathsection]isOpen) {
if ( self dataList[indexPathsection]isOpen) {
//设置展开的cell
}else{
//设置没有展开的cell;
}}
实现的方法和tableBView差不多,实现他的几个代理方法:
解释一下:传进来的item:代表他给你的model,根据这个model可以去获取上级model: clickpackagesModelpackageModel = [treeViewparentForItem:model];
同样可以根据model获取相应的cell: clickPackageCellpackagecell01 = (clickPackageCell)[treeViewcellForItem:model];
有了上面两个方法,基本就能玩转三级展开和收起;
对于三级展开,大家还有什么好的想法亦或者好的框架没?欢迎补充
先看以下的效果图
- (void)tableView:(UITableView)tableViewwillDisplayCell:(UITableViewCell)cellforRowAtIndexPath:(NSIndexPath)indexPath {
// 圆角角度
CGFloatradius =10f;
// 设置cell 背景色为透明
cellbackgroundColor = UIColorclearColor;
// 创建两个layer
CAShapeLayernormalLayer = [[CAShapeLayeralloc]init];
CAShapeLayerselectLayer = [[CAShapeLayeralloc]init];
// 获取显示区域大小
CGRectbounds =CGRectInset(cellbounds,10,0);
// 获取每组行数
NSIntegerrowNum = [tableViewnumberOfRowsInSection:indexPathsection];
// 贝塞尔曲线
UIBezierPathbezierPath =nil;
//考虑一行和多行的情况,若行数为1,则这个cell的每个角都是圆角,否则第一行的左上和右上为圆角,最后一行的左下和右下为圆角
if(rowNum ==1) {
// 一组只有一行(四个角全部为圆角)
bezierPath = [UIBezierPathbezierPathWithRoundedRect:bounds
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(radius, radius)];
}else{
if(indexPathrow==0) {
// 每组第一行(添加左上和右上的圆角)
bezierPath = [UIBezierPathbezierPathWithRoundedRect:bounds
byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
cornerRadii:CGSizeMake(radius, radius)];
}else if(indexPathrow== rowNum -1) {
// 每组最后一行(添加左下和右下的圆角)
bezierPath = [UIBezierPathbezierPathWithRoundedRect:bounds
byRoundingCorners:(UIRectCornerBottomLeft|UIRectCornerBottomRight)
cornerRadii:CGSizeMake(radius, radius)];
}else{
// 每组不是首位的行不设置圆角
bezierPath = [UIBezierPathbezierPathWithRect:bounds];
}
}
//将贝塞尔曲线的路径赋值给图层,并将图层添加到view
// 把已经绘制好的贝塞尔曲线路径赋值给图层,然后图层根据path进行图像渲染render
normalLayerpath= bezierPathCGPath;
selectLayerpath= bezierPathCGPath;
UIViewnomarBgView = [[UIViewalloc]initWithFrame:bounds];
// 设置填充颜色
normalLayerfillColor = [UIColor colorWithWhite:095 alpha:10]CGColor;
// 添加图层到nomarBgView中
[nomarBgViewlayerinsertSublayer:normalLayeratIndex:0];
nomarBgViewbackgroundColor = UIColorclearColor;
cellbackgroundView= nomarBgView;
//圆角显示就完成了,但是如果没有取消cell的点击效果,会出现一个灰色的长方形的形状,再用上面创建的selectLayer给cell添加一个selectedBackgroundView
UIViewselectBgView = [[UIViewalloc]initWithFrame:bounds];
selectLayerfillColor = [UIColor colorWithWhite:095 alpha:10]CGColor;
[selectBgViewlayerinsertSublayer:selectLayeratIndex:0];
selectBgViewbackgroundColor = UIColorclearColor;
cellselectedBackgroundView= selectBgView;
}
func tableView(_tableView:UITableView, willDisplay cell:UITableViewCell, forRowAt indexPath:IndexPath) {
// 圆角角度
let radius =calculate(w:350)
// 设置cell 背景色为透明
cellbackgroundColor = UIColorclear
// 创建两个layer
let normalLayer =CAShapeLayer()
let selectLayer =CAShapeLayer()
// 获取显示区域大小
let bounds = cellboundsinsetBy(dx:100, dy:0)
// 获取每组行数
let rowNum = tableViewnumberOfRows(inSection: indexPathsection)
// 贝塞尔曲线
var bezierPath:UIBezierPath
if(rowNum==1) {
// 一组只有一行(四个角全部为圆角)
bezierPath =UIBezierPath(roundedRect: bounds, byRoundingCorners: allCorners, cornerRadii:CGSize(width: radius, height: radius))
}else{
if(indexPathrow==0) {
// 每组第一行(添加左上和右上的圆角)
bezierPath =UIBezierPath(roundedRect: bounds, byRoundingCorners: [UIRectCornertopLeft,UIRectCornertopRight], cornerRadii:CGSize(width: radius, height: radius))
}elseif(indexPathrow==rowNum-1) {
// 每组最后一行(添加左下和右下的圆角)
bezierPath =UIBezierPath(roundedRect: bounds, byRoundingCorners: [UIRectCornerbottomLeft,UIRectCornerbottomRight], cornerRadii:CGSize(width: radius, height: radius))
}else{
// 每组不是首位的行不设置圆角
bezierPath =UIBezierPath(rect: bounds)
}
}
// 把已经绘制好的贝塞尔曲线路径赋值给图层,然后图层根据path进行图像渲染render
normalLayerpath= bezierPathcgPath;
selectLayerpath= bezierPathcgPath;
let nomarBgView =UIView(frame: bounds);
// 设置填充颜色
normalLayerfillColor=UIColorwhitecgColor
// 添加图层到nomarBgView中
nomarBgViewlayerinsertSublayer(normalLayer, at:0)
nomarBgViewbackgroundColor=UIColorclear
cellbackgroundView= nomarBgView
let selectBgView =UIView(frame: bounds)
selectLayerfillColor= UIColorwhitecgColor
selectBgViewlayerinsertSublayer(selectLayer, at:0)
selectBgViewbackgroundColor=UIColorclear
cellselectedBackgroundView= selectBgView
}
_deltaTimes = [NSMutableArray array]; NSInteger deltaMaxTimes = [selfvideoModeldeltaMaxTimes integerValue];
NSInteger deltaMinTimes = [selfvideoModeldeltaMinTimes integerValue];
for (NSInteger i = deltaMaxTimes; i >= deltaMinTimes; i--) {
[_deltaTimes addObject:[NSString stringWithFormat:@"%d", (int)i]];
}
}
return _deltaTimes;
}
#pragma mark - 获取视频状态
#pragma mark - <UITableViewDelegate,UITableViewDataSource>
- (NSInteger)numberOfSectionsInTableView:(UITableView )tableView {
return selftitlescount;
}
- (NSInteger)tableView:(UITableView )tableView numberOfRowsInSection:(NSInteger)section {
NSArray dataArray = selfdataArray[section];
return dataArraycount;
}
- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath )indexPath {
NSArray dataArray = selfdataArray[indexPathsection];
NSString text = dataArray[indexPathrow];
UITableViewCell cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
}
celltextLabeltext = text;
cellaccessoryType = UITableViewCellAccessoryNone;
cellselectionStyle = UITableViewCellSelectionStyleNone;
if (indexPathsection == 0) {
if ([text isEqualToString:selfcurrentState]) {
cellaccessoryType = UITableViewCellAccessoryCheckmark;
}
} else if (indexPathsection == 1) {
if ([text isEqualToString:[NSString stringWithFormat:@"%d", selfdeltaTimesIndex]]) {
cellaccessoryType = UITableViewCellAccessoryCheckmark;
}
}
return cell;
}
- (NSString )tableView:(UITableView )tableView titleForHeaderInSection:(NSInteger)section {
return selftitles[section];
}
- (void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath {
// 1取消所有的打钩
[tableView visibleCells];
[tableViewvisibleCells enumerateObjectsUsingBlock:^(UITableViewCell _Nonnull obj, NSUInteger idx, BOOL _Nonnull stop) {
objaccessoryType = UITableViewCellAccessoryNone;
}];
// 2打钩当前选中的行
UITableViewCell cell = [tableView cellForRowAtIndexPath:indexPath];
cellaccessoryType = UITableViewCellAccessoryCheckmark;
NSArray dataArray = selfdataArray[indexPathsection];
NSString text = dataArray[indexPathrow];
if (indexPathsection == 0) {
// 3发送状态指令
[self sendStateCommand:text];
} else if (indexPathsection == 1) {
selfdeltaTimesIndex = [text integerValue];
// 4发送调档指令
[self sendDeltaCommand:selfdeltaTimesIndex];
}
}
#pragma mark - 按钮点击事件
- (void)backButtonClicked {
[selfnavigationController popViewControllerAnimated:YES];
}
#pragma mark - 发送状态指令
- (void)sendStateCommand:(NSString )state
代理模式是一种消息传递方式,一个完整的代理模式包括:委托对象、代理对象和协议。
协议:用来指定代理双方可以做什么,必须做什么。
委托对象:根据指定的协议,指定代理去完成什么功能。
代理对象:根据指定的协议,完成委托方需要实现的功能。
从上图中可以看到三方之间的关系,在实际应用中通过协议来规定代理双方的行为,协议中的内容一般都是方法列表,当然也可以定义属性。
协议是公共的定义,如果只是某个类使用,我们常做的就是写在某个类中。如果是多个类都是用同一个协议,建议创建一个Protocol文件,在这个文件中定义协议。遵循的协议可以被继承,例如我们常用的 UITableView ,由于继承自 UIScrollView 的缘故,所以也将 UIScrollViewDelegate 继承了过来,我们可以通过代理方法获取 UITableView 偏移量等状态参数。
协议只能定义公用的一套接口,类似于一个约束代理双方的作用。但不能提供具体的实现方法,实现方法需要代理对象去实现。协议可以继承其他协议,并且可以继承多个协议,在iOS中对象是不支持多继承的,而协议可以多继承。
协议有两个修饰符 @optional 和 @required ,创建一个协议如果没有声明,默认是 @required 状态的。这两个修饰符只是约定代理是否强制需要遵守协议,如果 @required 状态的方法代理没有遵守,会报一个**的警告,只是起一个约束的作用,没有其他功能。
无论是 @optional 还是 @required ,在委托方调用代理方法时都需要做一个判断,判断代理是否实现当前方法,否则会导致崩溃。
在iOS中代理的本质就是代理对象内存的传递和 *** 作,我们在委托类设置代理对象后,实际上只是用一个id类型的指针将代理对象进行了一个弱引用。委托方让代理方执行 *** 作,实际上是在委托类中向这个id类型指针指向的对象发送消息,而这个id类型指针指向的对象,就是代理对象。
通过上面这张图我们发现,其实委托方的代理属性本质上就是代理对象自身,设置委托代理就是代理属性指针指向代理对象,相当于代理对象只是在委托方中调用自己的方法,如果方法没有实现就会导致崩溃。从崩溃的信息上来看,就可以看出来是代理方没有实现协议中的方法导致的崩溃。
而协议只是一种语法,是声明委托方中的代理属性可以调用协议中声明的方法,而协议中方法的实现还是有代理方完成,而协议方和委托方都不知道代理方有没有完成,也不需要知道怎么完成。
由于代理对象使用强引用指针,引用创建的委托方对象,并且成为委托对象的代理。这就会导致委托对象的delegate属性强引用代理对象,导致循环引用的问题,最终两个对象都无法正常释放。
我们将委托对象的delegate属性,设置为弱引用属性。
weak 和 assign 是一种“非拥有关系”的指针,通过这两种修饰符修饰的指针变量,都不会改变被引用对象的引用计数。但是在一个对象被释放后, weak 会自动将指针指向 nil ,而 assign 则不会。在iOS中,向 nil 发送消息时不会导致崩溃的,所以 assign 就会导致野指针的错误 unrecognized selector sent to instance 。
所以我们如果修饰代理属性,还是用 weak 修饰,比较安全。
以上就是关于tableView的section和row全部的内容,包括:tableView的section和row、webdeviceagent无法获得webview内容ios、如何计算uilabel里面文字的行数等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)