项目作者: leejayID

项目描述 :
【Objective-C 联动】:两个 TableView 之间的联动,TableView 与 CollectionView 之间的联动
高级语言: Objective-C
项目地址: git://github.com/leejayID/Linkage.git
创建时间: 2016-07-07T06:45:33Z
项目社区:https://github.com/leejayID/Linkage

开源协议:MIT License

关键词:
tableview-collectionview

下载


【Objective-C 联动】:两个 TableView 之间的联动,TableView 与 CollectionView 之间的联动

前言

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

本文仿造了美团外卖和礼物说,分别实现了两个 TableView 之间和 TablView 与 CollectionView 之间的联动效果,效果图看下面的 gif 图。先附上 gif 图的 demo 下载链接,【GitHub - OC 版】【GitHub - Swift 版】,配合 demo 一起看文章,效果会更佳。

联动.gif

正文

一、TableView 与 TableView 之间的联动

下面来说下实现两个 TableView 之间联动的主要思路:
先解析数据装入模型,objectWithDictionary:是将字典转化为模型,这个工具是我用 runtime 写的,一行代码解析数据,具体使用方法可以参考我简书上另一篇文章【Objective-C中的Runtime】

  1. NSString *path = [[NSBundle mainBundle] pathForResource:@"meituan" ofType:@"json"];
  2. NSData *data = [NSData dataWithContentsOfFile:path];
  3. NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
  4. NSArray *foods = dict[@"data"][@"food_spu_tags"];
  5. for (NSDictionary *dict in foods)
  6. {
  7. CategoryModel *model = [CategoryModel objectWithDictionary:dict];
  8. [self.categoryData addObject:model];
  9. NSMutableArray *datas = [NSMutableArray array];
  10. for (FoodModel *f_model in model.spus)
  11. {
  12. [datas addObject:f_model];
  13. }
  14. [self.foodData addObject:datas];
  15. }

定义两个 TableView:LeftTableView 和 RightTableView。

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  2. {
  3. if (_leftTableView == tableView)
  4. {
  5. LeftTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier_Left forIndexPath:indexPath];
  6. FoodModel *model = self.categoryData[indexPath.row];
  7. cell.name.text = model.name;
  8. return cell;
  9. }
  10. else
  11. {
  12. RightTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier_Right forIndexPath:indexPath];
  13. FoodModel *model = self.productData[indexPath.section][indexPath.row];
  14. cell.model = model;
  15. return cell;
  16. }
  17. }

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

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

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

  • 1.在 TableView 分区标题即将展示里面,判断当前的 tableView 是 RightTableView, RightTableView 滑动的方向向上,RightTableView 是用户拖拽而产生滚动的(主要判断 RightTableView 是用户拖拽的,还是点击 LeftTableView 滚动的),如果三者都成立,那么 LeftTableView 的选中行就是 RightTableView 的当前 section。
  • 2.在 TableView 分区标题展示结束里面,判断当前的 tableView 是 RightTableView,滑动的方向向下,RightTableView 是用户拖拽而产生滚动的,如果三者都成立,那么 LeftTableView 的选中行就是 RightTableView 的当前 section-1。
  1. // 标记一下 RightTableView 的滚动方向,是向上还是向下
  2. - (void)scrollViewDidScroll:(UIScrollView *)scrollView
  3. {
  4. static CGFloat lastOffsetY = 0;
  5. UITableView *tableView = (UITableView *) scrollView;
  6. if (_rightTableView == tableView)
  7. {
  8. _isScrollDown = lastOffsetY < scrollView.contentOffset.y;
  9. lastOffsetY = scrollView.contentOffset.y;
  10. }
  11. }
  12. // TableView 分区标题即将展示
  13. - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(nonnull UIView *)view forSection:(NSInteger)section
  14. {
  15. // 当前的 tableView 是 RightTableView,RightTableView 滚动的方向向上, RightTableView 是用户拖拽而产生滚动的((主要判断 RightTableView 用户拖拽而滚动的,还是点击 LeftTableView 而滚动的)
  16. if ((_rightTableView == tableView) && !_isScrollDown && _rightTableView.dragging)
  17. {
  18. [self selectRowAtIndexPath:section];
  19. }
  20. }
  21. // TableView 分区标题展示结束
  22. - (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section
  23. {
  24. // 当前的 tableView 是 RightTableView,RightTableView 滚动的方向向下, RightTableView 是用户拖拽而产生滚动的(主要判断 RightTableView 用户拖拽而滚动的,还是点击 LeftTableView 而滚动的)
  25. if ((_rightTableView == tableView) && _isScrollDown && _rightTableView.dragging)
  26. {
  27. [self selectRowAtIndexPath:section + 1];
  28. }
  29. }
  30. // 当拖动右边 TableView 的时候,处理左边 TableView
  31. - (void)selectRowAtIndexPath:(NSInteger)index
  32. {
  33. [_leftTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];
  34. }

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

二、TableView 与 CollectionView 之间的联动

TableView 与 CollectionView 之间的联动与两个 TableView 之间的联动逻辑类似。
下面说下实现 TableView 与 CollectionView 之间的联动的主要思路:
还是一样,先解析数据装入模型。

  1. NSString *path = [[NSBundle mainBundle] pathForResource:@"liwushuo" ofType:@"json"];
  2. NSData *data = [NSData dataWithContentsOfFile:path];
  3. NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
  4. NSArray *categories = dict[@"data"][@"categories"];
  5. for (NSDictionary *dict in categories)
  6. {
  7. CollectionCategoryModel *model = [CollectionCategoryModel objectWithDictionary:dict];
  8. [self.dataSource addObject:model];
  9. NSMutableArray *datas = [NSMutableArray array];
  10. for (SubCategoryModel *sModel in model.subcategories)
  11. {
  12. [datas addObject:sModel];
  13. }
  14. [self.collectionDatas addObject:datas];
  15. }

定义一个 TableView,一个 CollectionView。

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  2. {
  3. LeftTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier_Left forIndexPath:indexPath];
  4. CollectionCategoryModel *model = self.dataSource[indexPath.row];
  5. cell.name.text = model.name;
  6. return cell;
  7. }
  8. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  9. {
  10. CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier_CollectionView forIndexPath:indexPath];
  11. SubCategoryModel *model = self.collectionDatas[indexPath.section][indexPath.row];
  12. cell.model = model;
  13. return cell;
  14. }

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

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

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

  • 1.在 CollectionView 分区标题即将展示里面,判断 当前 CollectionView 滚动的方向向上, CollectionView 是用户拖拽而产生滚动的(主要是判断 CollectionView 是用户拖拽而滚动的,还是点击 TableView 而滚动的),如果二者都成立,那么 TableView 的选中行就是 CollectionView 的当前 section。
  • 2.在 CollectionView 分区标题展示结束里面,判断当前 CollectionView 滚动的方向向下, CollectionView 是用户拖拽而产生滚动的,如果二者都成立,那么 TableView 的选中行就是 CollectionView 的当前 section-1。
  1. // 标记一下 CollectionView 的滚动方向,是向上还是向下
  2. - (void)scrollViewDidScroll:(UIScrollView *)scrollView
  3. {
  4. static float lastOffsetY = 0;
  5. if (self.collectionView == scrollView)
  6. {
  7. _isScrollDown = lastOffsetY < scrollView.contentOffset.y;
  8. lastOffsetY = scrollView.contentOffset.y;
  9. }
  10. }
  11. // CollectionView 分区标题即将展示
  12. - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
  13. {
  14. // 当前 CollectionView 滚动的方向向上,CollectionView 是用户拖拽而产生滚动的(主要是判断 CollectionView 是用户拖拽而滚动的,还是点击 TableView 而滚动的)
  15. if (!_isScrollDown && collectionView.dragging)
  16. {
  17. [self selectRowAtIndexPath:indexPath.section];
  18. }
  19. }
  20. // CollectionView 分区标题展示结束
  21. - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(nonnull UICollectionReusableView *)view forElementOfKind:(nonnull NSString *)elementKind atIndexPath:(nonnull NSIndexPath *)indexPath
  22. {
  23. // 当前 CollectionView 滚动的方向向下,CollectionView 是用户拖拽而产生滚动的(主要是判断 CollectionView 是用户拖拽而滚动的,还是点击 TableView 而滚动的)
  24. if (_isScrollDown && collectionView.dragging)
  25. {
  26. [self selectRowAtIndexPath:indexPath.section + 1];
  27. }
  28. }
  29. // 当拖动 CollectionView 的时候,处理 TableView
  30. - (void)selectRowAtIndexPath:(NSInteger)index
  31. {
  32. [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];
  33. }

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

最后

由于笔者水平有限,文中如果有错误的地方,或者有更好的方法,还望大神指出。
附上本文的所有 demo 下载链接,【GitHub - OC 版】【GitHub - Swift 版】,配合 demo 一起看文章,效果会更佳。
如果你看完后觉得对你有所帮助,还望在 GitHub 上点个 star。赠人玫瑰,手有余香。

建议 & 支持

如有问题请与我联系