实现外卖选餐时两级 tableView 联动效果
最近实现了下饿了么中选餐时两级tableView联动效果,先上效果图,大家感受一下:

下面说下具体实现步骤:
首先分解一下,实现这个需求主要是两点,一是点击左边tableView,同时滚动右边tableView到具体的位置。二是拖动右边tableView选中左边tableView对应的某一行。要实现这个需求有一点很重要:左边的tableView每一行对应的是右边tableView的每个分区,OK,Just Do It.
实现点击左边tableView同时滚动右边tableView,很简单,只需要实现tableView的代理方法- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;然后在代理方法里边拿到右边的tableView,实现让其滚动到第indexPath.row分区,第0行即可,代码如下:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// 如果点击的是右边的tableView,不做任何处理
if (tableView == self.rightTableView) return;
// 点击左边的tableView,设置选中右边的tableView某一行。左边的tableView的每一行对应右边tableView的每个分区
[self.rightTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.row] animated:YES scrollPosition:UITableViewScrollPositionTop];
}
我们这里不处理右边tableView的点击事件,所以if (tableView == self.rightTableView) return;
接下来我们实现 拖动右边tableView选中左边tableView对应的某一行,我们要动态选中左边的tableView,就需要拿到现在滚动到了那个分区,UITableView有两个代理方法,- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section // 一个头标题即将显示的时候掉用和- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section // 一个头标题即将消失的时候掉用
利用这两个方法就可以拿到当前所在分区实现这个功能了。
但是我总觉得这个方法不好,还有个更简单的方法,其实tableView有个极不常用,但很牛X的方法,叫做indexPathsForVisibleRows,官方文档解释是:
The value of this property is an array of NSIndexPath objects each representing a row index and section index that together identify a visible row in the table view. If no rows are visible, the value is nil.
简单意思就是,它返回一个装着目前屏幕上可见的cell的indexPath集合。
好的,重点来了,拿到这个集合,不就能拿到目前屏幕上顶端的cell的indexpath了吗,那就如愿以偿的拿到现在所在第indexpath.section个分区了。
说了这么多,上代码:
#pragma mark - UIScrollViewDelegate
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{ // 监听tableView滑动
// 如果现在滑动的是左边的tableView,不做任何处理
if ((UITableView *)scrollView == self.leftTableView) return;
// 滚动右边tableView,设置选中左边的tableView某一行。indexPathsForVisibleRows属性返回屏幕上可见的cell的indexPath数组,利用这个属性就可以找到目前所在的分区
[self.leftTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:self.rightTableView.indexPathsForVisibleRows.firstObject.section inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}
稍微解释一下,首先监听scrollView的拖动,本demo不处理左边tableView的滚动,所以if ((UITableView *)scrollView == self.leftTableView) return;
self.rightTableView.indexPathsForVisibleRows.firstObject.section这句是拿到当前屏幕上可见cell的第一行cell所在的分区,然后让左边的tableView选中第0分区(它只有一个分区)的这一行就OK了。
欢迎收藏本文章,最后附上demo ,Github传送门:https://github.com/WZBbiao/WZBLinkageTableView
--------------这叫分割线---------------
补充下:下边评论提到说点击左边tableView的时候会有阴影效果,其实是这样的,点击左边的tableView,右边的tableView是从当前位置动画滚动到相应位置的,既然有滚动,就会调- (void)scrollViewDidScroll:(UIScrollView *)scrollView这个代理方法,说白了就是拖动了右边tableView,拖动右边的过程中会陆续选中左边。那我想大家就明白了。
如果不想要这个效果,有两个办法,一个是直接吧- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath中的动画滚动的属性animated值改成NO
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// 如果点击的是右边的tableView,不做任何处理
if (tableView == self.rightTableView) return;
// 点击左边的tableView,设置选中右边的tableView某一行。左边的tableView的每一行对应右边tableView的每个分区
[self.rightTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.row] animated:NO scrollPosition:UITableViewScrollPositionTop];
}
这样做右边的tableView就是无动画滚动了,也就不会再调scrollViewDidScroll:方法。但是如果还想右边tableViewyou滚动效果,另一种解决方法是:把- (void)scrollViewDidScroll:(UIScrollView *)scrollView方法换成- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView这个代理方法方法就行了。饿了么有的界面好像就是这样做的,但是有bug(估计饿了么没测出来),这个方法的注释为
// called when scroll view grinds to a halt 当滚动视图戛然而止
--有道翻译如是说
根据本人亲测,拖拽之后,这个方法调用与否在于你的手指是否在动画停止之前离开了屏幕,如果在动画结束之前手指离开屏幕,此方法调用没什么问题。but,如果动画已经停止,再把手指拿开,这个方法是不会调的。有图有真相:

解决这个bug的关键在于,让手指离开的时候手动调一次这个代理方法,那怎么才能知道手指什么时候离开呢?scrollView给我们了另一个代理方法:- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset这个方法在结束拖拽的时候调,正好解决了我们的问题:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
// 推拽将要结束的时候手动调一下这个方法
[self scrollViewDidEndDecelerating:scrollView];
}
Github已经更新,最新demo在这 https://github.com/WZBbiao/WZBLinkageTableView
实现外卖选餐时两级 tableView 联动效果的更多相关文章
- 仿饿了吗点餐界面两个ListView联动效果
这篇文章主要介绍了仿饿了点餐界面2个ListView联动效果的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 如图是效果图: 是仿饿了的点餐界面 1.点击左侧的ListView,通过在在适 ...
- iOS 类似美团外卖 app 两个 tableView 联动效果实现
写在前面 首先声明哈,不是广告,我就是用的时候觉得这个功能比较好玩,就想着实现了一下.效果如图: 接下来简单的说一下思路吧~ 大体思路 可能我们看到这种功能的实现的时候,首先想着的是我在这个控制器中左 ...
- iOS 类似外卖 两个tableView联动
在伯乐在线上看到一个挺好玩的文章,自己也参考文章实现了一下. 效果实现如图所示: 具体实现的内容可以参考原文,参考文章:<iOS 类似美团外卖 app 两个 tableView 联动效果实现&g ...
- 仿美团外卖,饿了吗 两个ListView联动,左边点击切换右边,右边滑动切换左边
先上效果图: 实现思路: 1.先说右边标题: 首先,右边的数据源集合中的Javabean中含有三个属性name,type,title,而每个条目中会默认含有一个标题. 如果这是第一个条目,就让标题显示 ...
- asp.net mvc 两级分类联动方法示例
前台视图代码 <%:Html.DropDownList("AwardClassMainID","请选择")%> <%:Html.DropDow ...
- vue项目两级全选(多级原理也一样),感觉有点意思,随手一记
需求: 首先说一下思路:我首先把数据列表两级遍历了一下,增加了一个checked属性来控制勾选和不勾线 this.productList.forEach((item)=>{ this.$set( ...
- iOS开发UI篇—使用picker View控件完成一个简单的选餐应用
iOS开发UI篇—使用picker View控件完成一个简单的选餐应用 一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162 ...
- ios 两个 TableView 之间的联动, TableView 与 CollectionView 之间的联动
两个 TableView 之间的联动, TableView 与 CollectionView 之间的联动 这是一个创建于 359 天前的主题,其中的信息可能已经有所发展或是发生改变. [联动] :两个 ...
- ipv4理论知识3-分类编址之两级编址
两级编制 分类编址时,同一网络中的所有地址都属于统一个地址块,而每个地址块包含两部分:网络标识和主机标识.网络标识指明了网络,主机标识则指明了连接到该网络的一台特定的主机.如下图描绘了分类编址中一个I ...
随机推荐
- SQL SERVER CXPACKET-Parallelism Wait Type 的惯用解决方案
最近我的两个库出现,出现较多的CXPACKET等待,在网上找了一下资料.其中有篇一个SQL Server专栏作家的文章不错,也解决了我的一些疑问,就翻译在这里. 翻译整理仅用于传播资讯之目的. 原文出 ...
- Safari不兼容Javascript中的Date问题
在IOS5以上版本(不包含IOS5)中的Safari浏览器能正确解释出Javascript中的 new Date('2013-10-21') 的日期对象,但是在IOS5版本里面的Safari解释new ...
- 双数组Trie树(DoubleArrayTrie)Java实现
http://www.hankcs.com/program/java/%E5%8F%8C%E6%95%B0%E7%BB%84trie%E6%A0%91doublearraytriejava%E5%AE ...
- [转]shell脚本每行的执行顺序是怎样
原文:https://blog.csdn.net/weixin_42609121/article/details/83028000 ---------------------------------- ...
- (转)Unity3D工程版本管理方案
自:http://blog.dou.li/unity3d%E5%B7%A5%E7%A8%8B%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86%E6%96%B9%E6%A1%88 ...
- Simple XOR Encryption/Decryption in C++ (And Several Other Languages)
For details on how to implement XOR encryption using Go, see this post. If you are looking for XOR e ...
- android学习四(Activity的生命周期)
要学好活动(Activity).就必需要了解android中Activity的声明周期.灵活的使用生命周期.能够开发出更好的程序,在android中是使用任务来管理活动的,一个任务就是一组存放在栈里的 ...
- STL 笔记(四) 迭代器 iterator
stl 中迭代器能够理解为面向对象版本号的广义指针,提供了对容器中的对象的訪问方法,能够遍历容器全部元素.也能够訪问随意元素.stl 迭代器有下面五种: Input iterators 仅仅读,输 ...
- Linux配置流程
Linux中常用操作命令 http://www.cnblogs.com/laov/p/3541414.html#zhiling Linux下安装jdk并配置环境变量 http://jingyan.ba ...
- Java 图片验证码工具
package com.microwisdom.utils; import java.awt.Color; import java.awt.Font; import java.awt.Graphics ...