自定义UITableView索引动画,实现饿了么菜单效果
2016-06-29 23:21
651 查看
授人以鱼不如授人以渔,“授”这个字,不敢当,只把做这个效果的思路和大家分享一下。
需求和饿了么商店菜单效果是一样一样的,如下图
废话少说,进入正题,分析如下:
从直观上看,该效果是由左右两个UITableView实现的。即leftTableView(也可以看做是索引表视图indexTableView)、rightTableView
需求1:当点击左边cell时,右边对应的cell会滑动到最顶端,例如点击主食,那么主食分类下的这组cell会滑动到顶端;
需求2:当点击左边cell时,cell会有一个标记,代表选中了当前cell,例如上图的蓝色矩形条;
需求3:当rightTableView滑动的时候,indexTableView要标记与rightTableView最上面cell对应的cell,例如rightTableView滑动停止时最上面的一个cell属于主食,那么indexTableView中主食这一cell应该被标记选中;
需求4:点击右边cell的蓝色加号,进行多项的选择(该需求不在本文讨论范围,本文只讨论联动的效果)
滑动相关
UITableView
UITableView继承与UIScrollView所以,查找的范围也包括UIScrollView.h,管它用不用的到,先找出来
位置相关,对于UITableVIew来说等同于NSIndexPath
最终敲定
实现需求1选定的API为:
实现代码:
实现需求2的方式比较简答,数据控制界面,再次不多说,不清楚的可以下载源码。
实现需求3选定的API为:
实现代码:
所以,对于索引UI需要的数据即为1.省份的简称province,2.是否在显示当前省份的城市is_selected(所有的城市数据中涉及到几个省份,索引项就有几个);对于右侧城市部分,则是以所在省份为分组依据分成的多组数据。
代码层面的操作如下:
感觉数据处理的思路比较暴力,也可能有我不知道的iOS官方封装好的API,有更好方式方法的朋友,还望不吝赐教
需求和饿了么商店菜单效果是一样一样的,如下图
一、需求分析
作为一个码农,当拿到一个任务的时候,第一要务必然是需求分析,略过这一步早早的开工,很大可能会给自己埋下大坑,最后还得自己填了这个坑。甚至可以说,需求分析占到整个开发周期的三分之一都不为过。明确需要做什么,就有了开发的方向,如果一开始就冲动开发,一边开发一边捋业务逻辑,脑袋频繁切换任务类型,这种形式的开发效率是很低的。好的开始,是成功的一半!废话少说,进入正题,分析如下:
从直观上看,该效果是由左右两个UITableView实现的。即leftTableView(也可以看做是索引表视图indexTableView)、rightTableView
需求1:当点击左边cell时,右边对应的cell会滑动到最顶端,例如点击主食,那么主食分类下的这组cell会滑动到顶端;
需求2:当点击左边cell时,cell会有一个标记,代表选中了当前cell,例如上图的蓝色矩形条;
需求3:当rightTableView滑动的时候,indexTableView要标记与rightTableView最上面cell对应的cell,例如rightTableView滑动停止时最上面的一个cell属于主食,那么indexTableView中主食这一cell应该被标记选中;
需求4:点击右边cell的蓝色加号,进行多项的选择(该需求不在本文讨论范围,本文只讨论联动的效果)
二、寻找满足需求可能需要的API
看需求1知道,当点击的时候需要滑动,既然要滑动,就需要知道滑动到什么位置,所以需要找的API有两种,一种和位置有关,一种和滑动有关。通过点击UITableView类进入UITableView.h找到如下API:滑动相关
UITableView
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated; - (void)scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated; - (void)selectRowAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition; - (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0); - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);
UITableView继承与UIScrollView所以,查找的范围也包括UIScrollView.h,管它用不用的到,先找出来
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;
位置相关,对于UITableVIew来说等同于NSIndexPath
- (nullable NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point; - (nullable NSIndexPath *)indexPathForCell:(UITableViewCell *)cell; - (nullable NSArray<NSIndexPath *> *)indexPathsForRowsInRect:(CGRect)rect; - (nullable NSIndexPath *)indexPathForPreferredFocusedViewInTableView:(UITableView *)tableView NS_AVAILABLE_IOS(9_0); - (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath; - (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0); @property (nonatomic, readonly, nullable) NSArray<NSIndexPath *> *indexPathsForVisibleRows;
最终敲定
实现需求1选定的API为:
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;
实现代码:
#pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (tableView == _indexTableView) { [self reloadSelectedCellAtIndex:indexPath.row]; NSIndexPath *toIndexPath = [NSIndexPath indexPathForRow:0 inSection:indexPath.row]; [_detailTableView scrollToRowAtIndexPath:toIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; } }
实现需求2的方式比较简答,数据控制界面,再次不多说,不清楚的可以下载源码。
实现需求3选定的API为:
@property (nonatomic, readonly, nullable) NSArray<NSIndexPath *> *indexPathsForVisibleRows;
实现代码:
#pragma mark - UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == _indexTableView) { _left_isScrolling = YES; } else { _left_isScrolling = NO; } if (scrollView == _detailTableView) { if (_left_isScrolling) { return; } //获取detail当前最上方显示的cell所在的indexPath NSArray *arr = [_detailTableView indexPathsForVisibleRows]; if (arr.count > 0) { NSIndexPath *tempPath = [arr objectAtIndex:0]; if (tempPath) { if (_last_indexPath.section != tempPath.section) {//减少tableView的刷洗次数,当section变化的时候才刷新 [self reloadSelectedCellAtIndex:tempPath.section]; 4000 _last_indexPath = tempPath; } } } } }
三、数据模拟,数据处理,以便于UI使用
假设后台给的未经处理的一组数据,需要将数据进行分组,重新组合成UI方便使用的数据样式。本例的UI左边需要一个索引数组,每个索引对应有某一共同特点的一组数据。Demo中我选用的样式是,省份的简称,和该省对应的城市名称。未经处理的数据单个元素模型如下:@interface DemoModel : NSObject @property (nonatomic ,copy) NSString *province; //省份的简称 @property (nonatomic ,copy) NSString *city_name; //城市的名字 @property (nonatomic ,assign) BOOL is_selected; //是否选中,用于左侧索引的选中效果判断 @end
所以,对于索引UI需要的数据即为1.省份的简称province,2.是否在显示当前省份的城市is_selected(所有的城市数据中涉及到几个省份,索引项就有几个);对于右侧城市部分,则是以所在省份为分组依据分成的多组数据。
代码层面的操作如下:
1.过滤掉数据中的重复省份的城市,每个涉及省份只留一个数据作为索引关键字(个人认为数据处理的核心代码)
//过滤数组中重复的元素,生成左边的索引关键字数组 - (NSArray *)filteredCityArrSourceArr:(NSArray *)sourceArr { NSMutableArray *resultArr = [NSMutableArray array]; //找出原始城市数据 NSMutableArray *originalCityArr = [NSMutableArray array]; for (DemoModel *model in sourceArr) { [originalCityArr addObject:model.province]; } //去掉重复的字符串元素 for (NSString *str in originalCityArr) { if (![resultArr containsObject:str]) { [resultArr addObject:str]; } else { continue; } } return resultArr; }
2.根据关键字将数组分组按省份组成二维数组
//创建二维数组 for (int i=0; i<keyArr.count; i++) { NSString *currentKey = keyArr[i]; NSMutableArray *tempArr = [NSMutableArray array]; for (DemoModel *model in originalData) { if ([model.province isEqualToString:currentKey]) { [tempArr addObject:model]; } } [self.detailArr addObject:tempArr]; }
3.合成索引数据
//合成indexArr,从二维数组中每组去一个model就ok了 for (int i = 0; i<self.detailArr.count; i++) { [self.indexArr addObject:self.detailArr[i][0]]; }
感觉数据处理的思路比较暴力,也可能有我不知道的iOS官方封装好的API,有更好方式方法的朋友,还望不吝赐教
四、结果展示
五、源码下载地址:
https://github.com/StrongerWM/IndexTableViewDemo相关文章推荐
- 我是运营,我没有假期
- DB2数据库的安装
- C#实现把指定数据写入串口
- “传奇”图象数据存储方式
- 修复mysql数据库
- 浅析SQL数据操作语句
- SQLServer 数据导入导出的几种方法小结
- 简述MySQL分片中快速数据迁移
- MySQL数据备份之mysqldump的使用详解
- C#实现窗体间传递数据实例
- C#中的委托数据类型简介
- SQL Server删除表及删除表中数据的方法
- SqlServer2008误操作数据(delete或者update)后恢复数据的方法
- 给你的数据库文件减肥
- Oracle数据更改后出错的解决方法
- Oracle数据库数据丢失恢复的几种方法总结
- C#将Sql数据保存到Excel文件中的方法
- C#实例代码之抽奖升级版可以经表格数据导入数据库,抽奖设置,补抽
- SQL Server简单实现数据的日报和月报功能
- MFC实现在文件尾追加数据的方法