ios两个tableview之间的联动,tableview与collectionview之间的联动

孙富有(iOS工程师) 孙富有(iOS工程师)     2022-09-17     779

关键词:

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

这是一个创建于 359 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

前言

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

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

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

技术分享

正文

一、 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 indexPathForRow: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 之间的联动就这么实现了,是不是也很简单。

在两个 tableview 控制器之间传递一个数字对象:IOS

】在两个tableview控制器之间传递一个数字对象:IOS【英文标题】:Passinganumberobjectbetweentwotableviewcontrollers:IOS【发布时间】:2012-01-0612:47:27【问题描述】:我是一个新手,试图将从视图控制器1中的表中选择的行号传递给第二个视... 查看详情

ios 5子视图在tableview单元格中的两个视图之间翻转

】ios5子视图在tableview单元格中的两个视图之间翻转【英文标题】:ios5subviewflipbetweentwoviewintableviewcell【发布时间】:2012-05-2509:12:13【问题描述】:我有包含自定义单元格的表格视图。当用户单击该行时,每个单元格都有我想要翻... 查看详情

iosscrollview嵌套tableview联动滑动的实现方案

参考技术A最近公司项目中要开发一个Scrollview嵌套多个TableView的页面。类似下图微博的这种页面。开发这样的结构会有一个问题就是滑动TableView到边界的时候,由于响应链问题,不会带动Scroll1继续滑动。最开始打算的是通过两个... 查看详情

在两个 TableView 之间传递数据

】在两个TableView之间传递数据【英文标题】:PassingDataBetweenTwoTableViews【发布时间】:2013-01-2417:03:12【问题描述】:我有一个ViewController包含两个TableViews,如下所示。所以最上面的表(firstTable)目前有两条记录。我想根据顶部的... 查看详情

如何删除 UIStackView 中两个 tableview 之间的空间?

】如何删除UIStackView中两个tableview之间的空间?【英文标题】:howtoremovespacebetweentwotableviewinUIStackView?【发布时间】:2018-01-2218:40:12【问题描述】:我正在使用两个UITableView。两个UITableView数据都来自数据库。因此,大小不固定。... 查看详情

PrepareForSegue 不在两个 TableView 控制器之间发送数据

】PrepareForSegue不在两个TableView控制器之间发送数据【英文标题】:PrepareForSeguenotsendingdatabetweentwoTableViewControllers【发布时间】:2017-03-1016:09:56【问题描述】:我正在尝试将测试变量传递给我的目标控制器,但测试不成功。我的表... 查看详情

IOS:两个tableview的tableview委托方法

】IOS:两个tableview的tableview委托方法【英文标题】:IOS:tableviewdelegatemethodsfortwotableview【发布时间】:2011-06-2911:11:11【问题描述】:我在一个类中为tableview提供了这些委托方法:-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableViewretur... 查看详情

我可以在 iphone 的 tableview 中的两个单元格之间留出空间吗?

】我可以在iphone的tableview中的两个单元格之间留出空间吗?【英文标题】:canigivespacebetweentwocellsintableviewinipohne?【发布时间】:2013-03-3011:17:41【问题描述】:staticNSString*CellIdentifier=@"Cell";UITableViewCell*cell=[tableViewdequeueReusableCellWithI... 查看详情

如何更改tableview单元格之间的空间ios swift

】如何更改tableview单元格之间的空间iosswift【英文标题】:HowcanIchangethespacebetweentableviewcellsiosswift【发布时间】:2015-11-2609:54:44【问题描述】:如何更改tableviewcontroller中单元格之间的间距?。我有一个使用Swift的应用程序。我添... 查看详情

tableview分组样式每组section之间距离的调整

参考技术A两个注意点:1.默认tableview分组样式,每组section有额外头部和尾部间距,如果每组之间的间距一致,可以调整tableview的两个属性sectionHeaderHeight和sectionFooterHeight2.如果有导航条和tabbar,tableview的内容视图也有自己额外的... 查看详情

如何在swift ios中的两个自定义表格视图单元格之间添加间距?

...之间添加间距?【英文标题】:HowtoaddspacinginbetweentwocustomTableviewcellsinswiftios?【发布时间】:2016-12-2108:28:17【问题描述】:funcnumberOfSections(intableView:UITableView)->Intreturn1functableView(_tableView:UITab 查看详情

在 iOS 中,如何在两个单元格中的文本字段之间切换?

...3-09-0221:46:43【问题描述】:我有一个使用自定义单元格的TableView的应用程序,每个单元格都包含一个文本字段。当用户点击一个单元格时,我想将相应的textField置于编辑模式。如果另一个单元格的textField已经处于编辑模式,我需... 查看详情

两个表之间的查询慢

】两个表之间的查询慢【英文标题】:QuerySlownessBetweenTwoTables【发布时间】:2021-04-1717:18:28【问题描述】:如果在我的"table1"和"table2"表中存在与"parent_id"的值匹配的结果,我想获取"table1"表中的行数。但是SQL查询耗时太长。table1... 查看详情

如何使用 iOS 故事板创建具有两个嵌套 tableview 单元格 xib 的单个 tableview?

】如何使用iOS故事板创建具有两个嵌套tableview单元格xib的单个tableview?【英文标题】:howtocreatesingletableviewwithtwonestedtableviewcellxibsusingiOSstoryboard?【发布时间】:2015-12-1005:12:02【问题描述】:我正在尝试使用父子自定义表格视图单... 查看详情

两个 data.table 数据集之间的快速映射

】两个data.table数据集之间的快速映射【英文标题】:Fastmappingbetweentwodata.tabledatasets【发布时间】:2017-01-2321:00:06【问题描述】:我想获取与数据集中所有邮政编码相关联的县名。我使用数据框获得了相对较快的结果(尽管我觉... 查看详情

两个表数据之间的映射

】两个表数据之间的映射【英文标题】:Mappingbetweentwotabledata【发布时间】:2016-09-2410:22:28【问题描述】:table1:name,address,phonetable2:name,location,mobiletable1只是一个空白数据的模式。table2有数据。我想将table2数据插入table1架构。如何... 查看详情

ios--tableview顶部留白

...下来之后需要适配系统,故此测试系统发现同一种机器上tableView与顶部控件,或者导航栏之间的有大量的留白;这个问题是有的界面有,有的界面无;修改与导航栏或者其他控件之间的距离也没有什么用;具体如下;最后发现是... 查看详情

PhpMyAdmin- 在两个表之间共享数据

】PhpMyAdmin-在两个表之间共享数据【英文标题】:PhpMyAdmin-Sharingdatabetweentwotables【发布时间】:2016-04-1315:44:07【问题描述】:我正在尝试使用来自table2(所有者)的id填充table1(视频游戏)的字段id_owner。table1的字段possessor包含与t... 查看详情