今天看到 iOS实现多个可变cell复杂界面的制作 这篇文章,大致看了一下源码。感觉没有真的解决问题,而且局限性很大,不能保证动态行高,性能也不是很好。今天结合我们自己的工程,谈谈使用tableView来构建复杂界面的局限性,换句话说,一旦视图足够复杂,我们就应该根据情况不同决定是否使用tableView,或者将固定的部分抽离出来,减少在tableView中的逻辑判断。
置顶:
WechatIMG19.jpeg1> 如何隐藏显示的视图?
// 因为你不知道是一个button,还是什么,所以传入id使用id类型,避免警告⚠️
- (void)hiddenView:(id)view constant:(NSLayoutConstraint)viewConstant{
viewConstant.constant = 0.0f;
view.hidden = YES;
}
2>五行文本如何展开和隐藏?
推荐一个第三方库 TLAttributedLabel。注意: 该库有很多内存泄漏的问题,请使用的同志自行修正。
3>类似iOS实现多个可变cell复杂界面的制作 博主这样的,既然都是行高,也不用动态计算的,我建议这样用:
如果界面有很多都是可以固定下来的。你比如说商品的图片,商品的名称,商品价格,商品是否减价等等信息。为何不单独出来成为一个视图。那就不需要加入到tableView的逻辑判断里了。剩下就是评论了,评论可以单独用tableView来处理,
为何不用枚举,在创建之初,就对数据进行处理,确定总共需加载的类型,最后就确定可能要加载cell的类型。对数据提早进行处理,能让开发人员在后期处理越舒服。 前期你做的越多,后期越好判断。无非是组合判断。
typedef NS_ENUM(NSInteger, NIMKitTeamCardRowItemType) {
TeamCardRowItemTypeCommon,
TeamCardRowItemTypeTeamMember,
TeamCardRowItemTypeRedButton,
TeamCardRowItemTypeBlueButton,
TeamCardRowItemTypeSwitch,
};
在控制器中你可能这样做:
WechatIMG16.jpeg对于复杂的View,你可以用storyboard或者xib进行布局,然后用类来绑定视图,把界面元素都划分为不同的类(利用storyboard、xib和代码),这样容易维护。
下边用项目中真实的例子,看一下究竟怎么做更加合理。
WechatIMG6.jpeg WechatIMG7.jpeg WechatIMG8.jpeg
分析界面元素如下:
- 1:顶部为滚动视图,展示产品相关信息。(固定)
- 2:轮次,浏览次数,关注都是固定的。打码的地方也是固定的,可以为一个或者是两个元素。(固定)
- 3:紧接下来的项目定位(不固定)、项目介绍(不固定)、核心竞争力(不固定),团队介绍(不固定)等等都是不确定是否存在的信息。每个点如果超过五行就必须有阅读更多的点击事件,展开相应的更多信息(不固定)。
- 4:更多信息,根据服务端返回的数据,确定是否展示。(不固定)
- 5:相关链接,可有可无。(不固定)
- 6:相似项目,可有可无。(不固定)
如此多的不固定因素,加之行高信息。那么使用tableView作为整体的大结构,显然是不适合的。为什么呢? 因为行数不确定,行高不确定,内容不确定。这种条件下,如果使用tableView作为整体的大结构,需要做N多的逻辑判断。最后随着版本的迭代很难调整。为以后的产品更迭埋下了大坑。
那么怎么解决这个问题,解决思路的宗旨是:尽量减少逻辑判断。避免更多的耦合。
-
1:固定的视图进行封装,隔离出来。
-
2: 不固定的视图单独处理。设置约束信息等。
-
3:整体采用scrollView作为底视图,在其上进行视图的添加和移除操作。
-
4:鉴于产品还有一个特殊的功能:在向下滚动的时候,顶部的滚动视图是遮盖在- 滚上来视图的下边的,给人一种遮盖的效果。最上边需要固定一个View用于展示。
这个对XIB 使用约束的要求相对高一点,必须熟练。然后理清楚视图和视图之间的关系之后就可以根据UI规范进行约束的调整了。
最后在config文件中,配置视图的一些信息。比如:
WechatIMG10.jpeg在我上一家公司中,在订单界面,因为逻辑很复杂,而且需求变更比较频繁,所以也是采用这种方式去解决问题。最后我们需要改动的地方真的很少,除非是大动,否则只需要在xib中重新设置约束就可以了。
WechatIMG11.jpeg
网友评论
言归正传,我觉得你的一些观点有失偏颇。
首先,我不明白你说的“没有真的解决问题”是指什么?你所谓的要解决的问题是什么?我的文章中给出的问题,我已经是用我所说的方法解决了,所以,你这边所说的应该是指另外的问题,或者说,你觉得我的方法通用性不够好,在面临其他一些相似问题时,解决起来就会力不从心,有局限性,关于这一点我后面再说。
“不能保证动态行高”,这点我觉得很奇怪,我的文章中有给出动态行高的例子,评论的内容就是动态行高,不明白为什么你说不能保证。有的cell是固定行高,这也是有意为之,我想传达的是,既可以用固定行高,也可以用动态行高。
“性能也不是很好”,我不知道你如何得出这样的结论。单从性能而言,我反而觉得你这种方法性能才会不好。因为你用scrollview,是不能像tableview那样实现cell的复用。比如你的示例中,“项目定位”、“项目介绍”、“团队介绍”这些如果是tableview的cell就可以复用,而用scrollview的话,就不行了。当然,客观的说,对于复杂界面,cell的复用本来就很有限,而且会用到大量不同的cell,与scrollview的方法相比,性能的优劣恐怕也难以定论。
你的方法总的思路就是“分而治之”,将一个界面划成各个小的View,然后各个View管理自身的逻辑就够了,将一个大问题拆成多个小问题。而我的做法,则简单粗暴,所有的逻辑都放一起处理,所以你会觉得需要做N多的逻辑判断,为以后的产品更迭埋下了大坑。
这几天,陆续看了些对我那种方法的评论,我发现,这里面存在一些误解,或者说我没有有意识的说明。我想说的是,我的方法并不适用所有情况,也不是要解决所有的问题。就好像说我的方法是一把切菜的刀,而你说它剁不了骨头一样,它本来就不是用来剁骨头的。我的方法是有局限的,正如我的文章中所给出的示例问题,只是一个cell多变但纯展示的界面。而你给出的示例,除了cell多变,还有比较多的交互,比如显示/隐藏内容、需要填写很多表单项等,这时我的方法就不合适。
总的来说,我觉得这都是一种权衡,需要根据自身的情境去考虑。比如团队的开发习惯,我的团队比较不习惯用scrollview,自然解决方法就会向tableview靠。比如团队技能、学习成本,正如你所说,你的这种方法,需要能熟练使用约束,这就是一种技能要求,一种门槛,会对团队开发、新人融入产生影响。此外,我猜想(因为没有示例代码),你可能封装了某些约束的操作,可能是像对应的View为hidden时,就自动调整高度为0以及和顶上View的间距。否则像“项目定位”、“项目介绍”、“核心竞争力”,“团队介绍”等这种不固定出现的,如果都靠手工判断调整约束去隐藏,显然是很麻烦。如果是有实现这样的封装,那显然实现上也需要时间精力,还要向团队成员传达这种用法,这也是要考虑的因素。对我而言,目前没有这样cell多变而交互又比较多的界面需要处理。我的方法足够解决我遇到的问题,对于增加、删除、调整cell顺序这样的需求变动,修改也在可控范围,并且解决方法也足够简单傻瓜化,团队成员能够快速上手、维护这一块东西,我就“适可而止”,没有必要去设计更通用的方案了。
至于为什么不单独出来成为一个视图,我那个文章开始提的HeaderView + AutoLayout的方法,就跟单独出来成为一个视图是类似的(只不过,我那种做法视图粒度太粗犷了)。另外,在使用cell时,我也有提到,cell的粒度是可以自行选择,把“商品图片”、“商品名称”、“商品价格”等这几个做成一个cell也是可以的,这也跟你的单独成一个视图的思路是一样。而最终选择拆分成那么细碎的cell,是有几点原因:
1. 在数据项是否显示上,摆脱对约束的操控。单独视图如果某些项不显示,那么需要对约束做比较多的操作。以你的界面为例,如果“项目介绍”不出现,需要把“项目介绍”这一项的高度约束设置为0,最好还要把“项目介绍”的子View全部移除(否则,子View里的约束可能会因为父View高度约束设置为0而出现约束冲突。当然,如果你的界面要求是有展开/隐藏功能,那就不能移除子View了)。“项目介绍”和上面的“项目定位”间距约束设置为0,“项目介绍”的hidden设置为yes(减少视图绘制)。我觉得这样太麻烦,所以,就想每一小块都做成一个cell,就不用操心这些约束的问题。
2. 更好的复用。cell分得细,复用性就越高,比如我的界面中“商品名称”、“副标题”这两部分也可以复用(虽然最终没有选择复用),评论内容部分可以复用。像你的界面,“项目定位”、“项目介绍”、“团队介绍”等这些如果用cell来做,也是可以复用的。cell复用在一定程度能保证性能。
3. 更方便调整数据项的显示顺序。操蛋的产品经理或是领导,有时脑袋一拍,觉得某个项放前面更好,比如像你的界面,如果要把“项目定位”和“项目介绍”位置对调,那么你就需要在xib上调整约束。这虽然没什么难度,但却是令人厌烦的体力活。如果位置的调整比较多,或者比较频繁,那么也是让人抓狂。我的方法就比较简便,调整一下拼凑cell数据的代码块顺序,基本上就是剪切粘贴就搞定了。
4. 可以更好应对相似而不相同的界面。在我的需求中,像商品详情这样相似的界面有好几个,因为商品是有不同类型,比如有的是普通商品、有的是免费专区商品、有的是特惠专区商品等,不同类型商品的显示上会略有不同。比如免费专区的商品就不显示价格,而是在价格那一行显示其他信息,这种如果用单独视图来做,那么视情况,对约束的操作可能会很麻烦。再者,有的类型还涉及到显示顺序调整。试想一下,如果你的界面中,有时要把“项目介绍”放前面,有时要把“项目定位”放前面,甚至更多的数据项显示顺序需要动态调整(注意,这是动态调整,要根据不同类型显示不同顺序,而不是像第3点描述的那种,在设计时静态调整好就可以),那么我想,你这要去操作约束,也是很抓狂的。
5. 更“积木化”。这一点其实也是跟第4点息息相关,细小的cell使得界面可以随意拼凑,灵活性较高。试想一下,如果你的界面需求更变态点,有时显示的时候,要把“项目介绍”移到其他独立视图中,那么我想你就不是抓狂,而是吐血三升了。
总的来说,还是那句老话,看自己的情境。我面临的需求是,界面多变但纯展示,还可能有相似又不同的界面,而我有自己的考量,我希望调整顺序时能比较简便,我希望解决方法能比较简单,方便团队成员上手及维护等,基于此,我觉得我的方法就是最好的选择了。
1: 因为不确定,所以视图添加和移除都是不固定的,所以最后整个界面的高度也就无法计算,或者计算起来觉得很麻烦,所以就托管给tableView来做处理,tableView会根据行高和行数进行高度计算,但是scrollView的优势就在于复杂界面布局可以交给AutoLayout,逻辑判断很少,只要拿到数据对数据进行处理即可。
2:其实您的界面有很多都是可以固定下来的。你比如说商品的图片,商品的名称,商品价格,商品是否减价等等信息。为何不单独出来成为一个视图,这样会不会更好,您觉得呢?这些基本可以确定是一个商品的基本属性,不是吗?基本不会出现不存在的现象吧。那就不需要加入到tableView的逻辑判断里了。剩下就是评论了,评论可以单独用tableView来处理,不是吗。
3: 感谢交流。