需求背景
想要参考大众点评实现一个类似的多级菜单的功能,网上找了很久都没有找到合适的,就自己动手实现了。一开始乍看之下觉得挺简单,但细写后发现里面的东西还是挺丰富的,所以记录下类似的实现思路供兄弟们参考。
实现效果图
菜单设计思路
1. 处理数据源
一个比较重要的思想是不管几个列表,每一个cell都可以看成对应一个Model,整个菜单都以一个model进行设计。在这里我的整个模型设计为:
@interface JNLifeTransModel : NSObject
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *idString;
@property (nonatomic, assign) BOOL selected;
@property (nonatomic, strong) NSString *longitude;
@property (nonatomic, strong) NSString *latitude;
@property (nonatomic, strong) NSMutableArray<JNLifeTransModel *> *transItems;
@end
这样设计可以思考为,第一个列表中的每一个cell当它被选中时,都会取出其中对应的下一个列表,依次类推。在我的例子中,距离/地铁其实对应的数据源一开始不是JNLifeTransModel,但是可以通用转换把相关的数据都处理为这个菜单对应的数据源。
2. 利用索引去进行选中和未选中的处理
当我们处理一个列表其中某一个cell选中时,可以先遍历整个数据源将其设置为选中,然后根据点击的索引将选中的cell置为选中状态。
上述这种处理方式针对简单列表的实现当然是可以的,但这里地铁线路包含的数据量实际上是很大的,每一条线路都对应着很多的站点,利用循环的方案去解决问题在性能上是很低的,所以我采用了另一个比较好的方案就是记录当前用户的选择,并且记录上一次用户的选择。 我这里有三个tableView,用户每一个列表的选中实际上都对应着一个索引,比如选择地铁1号线AAA这个选项时,其索引应该为(1,1,0),此时如果用户选择了地铁1号线BBB,那么索引为(1,1,1),上一个记录的索引为(1,1,0),我们应该把当前的索引(1,1,1)置为选中,然后将上一次的(1,1,0)置为未选中,就可以完成我们的需求。 索引的初始化比较重要,我的需求是当用户选择距离/地铁,默认选中距离-不限,所以我的索引初始化为:
self.table1PreIndex = 0;
self.table2PreIndex = 0;
self.table3PreIndex = -1;
self.table1Index = 0;
self.table2Index = 0;
self.table3Index = -1;
-1表示列表为被选中,如果需求要求为默认选中地铁1号线AAA,那么此时的初始化索引应该为:
self.table1PreIndex = 0;
self.table2PreIndex = 0;
self.table3PreIndex = -1;
self.table1Index = 1;
self.table2Index = 1;
self.table3Index = 0;
3. 关于列表选中的处理
关于某一个列表选中某一个cell时,此时有一个比较重要的点在于对列表的刷新判断。当我选择距离/地铁-地铁这个选项时,实际上我需要刷新三个列表。当我选择距离/地铁-地铁-1号线时,实际上我需要刷新第二和第三个列表,当我选择距离/地铁-地铁-1号线-AAA时,实际上我只需刷新第三个列表。因为子列表的选中不会影响上级列表的变化,所以并不需要每一个列表都进行刷新。
4. 关于回显的处理
关于回显的处理,需要注意的是,回显的时候不需要用到前一个选中的索引,只需要用户最后确认时的索引即可。 另一个可能引起很多问题的地方是,一定要注意对于重置选中cell的触发条件,在我的需求中,有几种情况会触发重置cell,分别是:选中第三个列表、触摸背景区域让菜单栏消失、点击全部类型按钮、点击距离/地铁按钮,这四种情况都要重置用户上一个选中时的索引,这对于处理回显有很大的影响,其中只有用户选择具体距离(比如1KM)或选择地铁-不限或某一个地铁站时,我才应该记录当前用户的选项,否则类似于点击背景区域让菜单栏消失,不应该再去记录当前用户的选择,用户的选择应该还是停留在之前的选中状态。
总结
综上所述,我对于多级菜单的实现思路就可以分为下面几步:
- 数据源的处理
- 定义各列表选中和未选中的索引
- 选中某列表中的某个cell的处理
- 回显和影响重置前一个选中状态的条件处理
Demo地址
https://github.com/jniosdeveloper/DzdpMultiLevelMenuDemo