两个 TableView 之间的联动, TableView 与 CollectionView 之间的联动 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
kengsir
V2EX    iDev

两个 TableView 之间的联动, TableView 与 CollectionView 之间的联动

  •  
  •   kengsir 2016-09-06 12:01:30 +08:00 3180 次点击
    这是一个创建于 3375 天前的主题,其中的信息可能已经有所发展或是发生改变。

    [联动] :两个 TableView 之间的联动, TableView 与 CollectionView 之间的联动

    前言

    现在市面上有很多 app 都有联动功能,有的是两个 TableView 之间的联动,比如美团外卖,百度外卖,饿了么等等。有的是 TableView 与 CollectionView 之间的联动,比如礼物说等等。

    本文仿造了美团外卖和礼物说,分别实现了两个 TableView 之间和 TablView 与 CollectionView 之间的联动效果,效果图看下面的 gif 图。

    先附上 gif 图的 demo 下载链接, [ Code4App ] 配合 demo 一起看文章,效果会更佳。

    Usage

    正文

    一、 TableView 与 TableView 之间的联动

    下面来说下实现两个 TableView 之间联动的主要思路:

    先解析数据装入模型,objectWithDictionary:是将字典转化为模型,这个工具是我用 runtime 写的,一行代码解析数据,具体使用方法可以参考我简书上另一篇文章 [ Objective-C 中的 Runtime ]

    NSString *path = [[NSBundle mainBundle] pathForResource:@"meituan" ofType:@"json"]; NSData *data = [NSData dataWithContentsOfFile:path]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSArray *foods = dict[@"data"][@"food_spu_tags"]; for (NSDictionary *dict in foods) { CategoryModel *model = [CategoryModel objectWithDictionary:dict]; [self.categoryData addObject:model]; NSMutableArray *datas = [NSMutableArray array]; for (FoodModel *f_model in model.spus) { [datas addObject:f_model]; } [self.foodData addObject:datas]; } 

    定义两个 TableView : LeftTableView 和 RightTableView 。

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (_leftTableView == tableView) { LeftTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier_Left forIndexPath:indexPath]; FoodModel *model = self.categoryData[indexPath.row]; cell.name.text = model.name; return cell; } else { RightTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier_Right forIndexPath:indexPath]; FoodModel *model = self.productData[indexPath.section][indexPath.row]; cell.model = model; return cell; } } 

    先将左边的 TableView 关联右边的 TableView :点击左边的 TableViewCell ,右边的 TableView 跳到相应的分区列表头部。

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath { if (_leftTableView == tableView) { _selectIndex = indexPath.row; [_rightTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:_selectIndex] atScrollPosition:UITableViewScrollPositionTop animated:YES]; } } 

    再将右边的 TableView 关联左边的 TableView :标记一下 RightTableView 的滚动方向,然后分别在 TableView 分区标题即将展示和展示结束的代理函数里面处理逻辑。

    • 1.在 TableView 分区标题即将展示里面,判断当前的 tableView 是 RightTableView , RightTableView 滑动的方向向上, RightTableView 是用户拖拽而产生滚动的(主要判断 RightTableView 是用户拖拽的,还是点击 LeftTableView 滚动的),如果三者都成立,那么 LeftTableView 的选中行就是 RightTableView 的当前 section 。
    • 2.在 TableView 分区标题展示结束里面,判断当前的 tableView 是 RightTableView ,滑动的方向向下, RightTableView 是用户拖拽而产生滚动的,如果三者都成立,那么 LeftTableView 的选中行就是 RightTableView 的当前 section-1 。
    // 标记一下 RightTableView 的滚动方向,是向上还是向下 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { static CGFloat lastOffsetY = 0; UITableView *tableView = (UITableView *) scrollView; if (_rightTableView == tableView) { _isScrollDown = lastOffsetY < scrollView.contentOffset.y; lastOffsetY = scrollView.contentOffset.y; } } // TableView 分区标题即将展示 - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(nonnull UIView *)view forSection:(NSInteger)section { // 当前的 tableView 是 RightTableView , RightTableView 滚动的方向向上, RightTableView 是用户拖拽而产生滚动的((主要判断 RightTableView 用户拖拽而滚动的,还是点击 LeftTableView 而滚动的) if ((_rightTableView == tableView) && !_isScrollDown && _rightTableView.dragging) { [self selectRowAtIndexPath:section]; } } // TableView 分区标题展示结束 - (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section { // 当前的 tableView 是 RightTableView , RightTableView 滚动的方向向下, RightTableView 是用户拖拽而产生滚动的(主要判断 RightTableView 用户拖拽而滚动的,还是点击 LeftTableView 而滚动的) if ((_rightTableView == tableView) && _isScrollDown && _rightTableView.dragging) { [self selectRowAtIndexPath:section + 1]; } } // 当拖动右边 TableView 的时候,处理左边 TableView - (void)selectRowAtIndexPath:(NSInteger)index { [_leftTableView selectRowAtIndexPath:[NSIndexPath indexPathorRow:index inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop]; } 

    这样就实现了两个 TableView 之间的联动,是不是很简单。

    二、 TableView 与 CollectionView 之间的联动

    TableView 与 CollectionView 之间的联动与两个 TableView 之间的联动逻辑类似。

    下面说下实现 TableView 与 CollectionView 之间的联动的主要思路:

    还是一样,先解析数据装入模型。

    NSString *path = [[NSBundle mainBundle] pathForResource:@"liwushuo" ofType:@"json"]; NSData *data = [NSData dataWithContentsOfFile:path]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSArray *categories = dict[@"data"][@"categories"]; for (NSDictionary *dict in categories) { CollectionCategoryModel *model = [CollectionCategoryModel objectWithDictionary:dict]; [self.dataSource addObject:model]; NSMutableArray *datas = [NSMutableArray array]; for (SubCategoryModel *sModel in model.subcategories) { [datas addObject:sModel]; } [self.collectionDatas addObject:datas]; } 

    定义一个 TableView ,一个 CollectionView 。

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { LeftTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier_Left forIndexPath:indexPath]; CollectionCategoryModel *model = self.dataSource[indexPath.row]; cell.name.text = model.name; return cell; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier_CollectionView forIndexPath:indexPath]; SubCategoryModel *model = self.collectionDatas[indexPath.section][indexPath.row]; cell.model = model; return cell; } 

    先将 TableView 关联 CollectionView ,点击 TableViewCell ,右边的 CollectionView 跳到相应的分区列表头部。

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { _selectIndex = indexPath.row; [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:_selectIndex] atScrollPosition:UICollectionViewScrollPositionTop animated:YES]; } 

    再将 CollectionView 关联 TableView ,标记一下 RightTableView 的滚动方向,然后分别在 CollectionView 分区标题即将展示和展示结束的代理函数里面处理逻辑。

    • 1.在 CollectionView 分区标题即将展示里面,判断 当前 CollectionView 滚动的方向向上, CollectionView 是用户拖拽而产生滚动的(主要是判断 CollectionView 是用户拖拽而滚动的,还是点击 TableView 而滚动的),如果二者都成立,那么 TableView 的选中行就是 CollectionView 的当前 section 。
    • 2.在 CollectionView 分区标题展示结束里面,判断当前 CollectionView 滚动的方向向下, CollectionView 是用户拖拽而产生滚动的,如果二者都成立,那么 TableView 的选中行就是 CollectionView 的当前 section-1 。
    // 标记一下 CollectionView 的滚动方向,是向上还是向下 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { static float lastOffsetY = 0; if (self.collectiOnView== scrollView) { _isScrollDown = lastOffsetY < scrollView.contentOffset.y; lastOffsetY = scrollView.contentOffset.y; } } // CollectionView 分区标题即将展示 - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath { // 当前 CollectionView 滚动的方向向上, CollectionView 是用户拖拽而产生滚动的(主要是判断 CollectionView 是用户拖拽而滚动的,还是点击 TableView 而滚动的) if (!_isScrollDown && collectionView.dragging) { [self selectRowAtIndexPath:indexPath.section]; } } // CollectionView 分区标题展示结束 - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(nonnull UICollectionReusableView *)view forElementOfKind:(nonnull NSString *)elementKind atIndexPath:(nonnull NSIndexPath *)indexPath { // 当前 CollectionView 滚动的方向向下, CollectionView 是用户拖拽而产生滚动的(主要是判断 CollectionView 是用户拖拽而滚动的,还是点击 TableView 而滚动的) if (_isScrollDown && collectionView.dragging) { [self selectRowAtIndexPath:indexPath.section + 1]; } } // 当拖动 CollectionView 的时候,处理 TableView - (void)selectRowAtIndexPath:(NSInteger)index { [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle]; } 

    TableView 与 CollectionView 之间的联动就这么实现了,是不是也很简单。

    最后

    由于笔者水平有限,文中如果有错误的地方,或者有更好的方法,还望大神指正。

    附上本文的所有 demo 下载链接, [ Code4App ] ,配合 demo 一起看文章,效果会更佳。(本文授权发表于@code4app)

    damean
        1
    damean  
       2016-09-06 16:04:15 +08:00
    亮点在哪里??这种也需要写文章。。。
    kitalphaj
        2
    kitalphaj  
       2016-09-07 08:40:59 +08:00
    这种当然可以写文章。。。如果楼主能把这种方法封装成一个库就好了,哈哈
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4012 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 05:31 PVG 13:31 LAX 21:31 JFK 00:31
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86