热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【iOS开发实战】经典的外卖列表(双Table联动)

2019独角兽企业重金招聘Python工程师标准我们经常使用美团外卖、饿了么、口碑等外卖软件点餐,几乎所有的外卖软件所展示的商品类别都无一例外,采

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

        我们经常使用美团外卖、饿了么、口碑等外卖软件点餐,几乎所有的外卖软件所展示的商品类别都无一例外,采用双列表的形式呈现,商品的分类,以及对商品的下单操作。我们拿美团外卖为例,截图如下:

173731_uy0w_2279344.jpeg

暂时忽略头部视图,只关注下面的商品分组列表。

思路:

        在开始之前,我们首先应该思考其实现的流程和可能遇到的问题!首先映入眼帘的是左侧的商品分类列表,以及右侧的分区展现的商品列表。所以:

  • 我们至少需要两个tableView,单纯的放上两个tableView还不能满足实际需求。
  • 拿美团外卖这个界面来看,点击左侧商品分类,右侧的商品列表会将该分类的分区第一条数据滚动至右侧tableView的顶部。用户滚动右侧列表,左侧分类列表会随之高亮显示相应的分类标签。可以通过UITableViewDelegate的协议,即分区头、脚视图的显示周期,以及UIScrollViewDelegate的相应协议来实现左侧和右侧列表的联动。并结合tableView的滚动方法实现双列表的联动效果。
  • //分区头视图将要显示
    - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
    //分区脚视图已经结束显示
    - (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section
    //以及结束减速
    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

    //滚动至某一行
    - (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

     

实践:

1、创建两个tableView:

  •     为了尽可能简单实现,我们采用StoryBoard来创建这两个tableView(当然你也可以使用代码来创建),左侧tableView宽度为固定宽度100,右侧tableView宽度为剩余屏幕宽度,这里采用自动布局技术约束(这里不再赘述其实现过程)。如下图所示:


180735_sMdI_2279344.png

181152_fxZp_2279344.png

两个tableView布局、delegate的连接 及 关联代码

2、模拟分类的商品数据

_relate = YES;
goodsList = @[@{@"title" : @"精选特卖",@"list" : @[@"甜点组合", @"毛肚", @"菌汤", @"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤"]},@{@"title" : @"饭后(含有茶点)",@"list" : @[@"甜点组合", @"毛肚", @"菌汤"]},@{@"title" : @"茶点(含有茶点)",@"list" : @[@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤"]},@{@"title" : @"素材水果拼盘",@"list" : @[@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤",]},@{@"title" : @"水果拼盘生鲜果",@"list" : @[@"甜点组合", @"毛肚", @"菌汤",]},@{@"title" : @"拼盘",@"list" : @[@"甜点组合"]},@{@"title" : @"烤鱼盘",@"list" : @[@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤"]},@{@"title" : @"饮料",@"list": @[@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤",@"甜点组合", @"毛肚", @"菌汤"]},@{@"title": @"小吃",@"list": @[@"甜点组合", @"毛肚"]},@{@"title" : @"作料",@"list" : @[@"甜点组合", @"毛肚", @"菌汤"]},@{@"title" : @"主食",@"list" : @[@"甜点组合", @"毛肚", @"菌汤"]},];


3、绘制两tableView

  •     首先别忘了让ViewController遵守tableView的delegate:

181336_GF2h_2279344.png

  • 分区数、行数的实现:

//分区数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{if (tableView==_leftTableView) {return 1;}return goodsList.count;
}//行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{if (tableView==_leftTableView) {return goodsList.count;}return [[goodsList[section] objectForKey:@"list"] count];
}

  • 单元格内容的实现,这里只使用系统简单的cell风格,左侧cell高度默认80,右侧默认100,如下图所示:

//单元格内容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];if (cell==nil) {cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];}if (tableView==_leftTableView) {//分类标题cell.textLabel.text = [goodsList[indexPath.row] objectForKey:@"title"];}else{//商品标题cell.textLabel.text = [[goodsList[indexPath.section] objectForKey:@"list"] objectAtIndex:indexPath.row];}return cell;
}//行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{if (tableView==_leftTableView) {return 80;}return 100;
}

    测试运行工程可以看到一个简单的双列表已经呈现在你的面前,如下图所示:

184514_nRSe_2279344.png

  • 绘制分区头视图,高度设置为30:

//分区头视图
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{if (tableView==_rightTableView) {UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _rightTableView.bounds.size.width, 30)];view.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.9];UILabel * label = [[UILabel alloc] initWithFrame:view.bounds];[view addSubview:label];label.text = [goodsList[section] objectForKey:@"title"];return view;}return nil;
}//分区头视图高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{if (tableView==_leftTableView) {return CGFLOAT_MIN;}return 30;
}//脚视图高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{if (tableView == self.leftTableView) {return 0;} else {//重要return CGFLOAT_MIN;}
}

       

    至此,两个tableView的绘制完成了,接下来解决联动的问题吧。

184546_wTzx_2279344.png

4、两个tableView的联动

    首先定义一个BOOL类型的变量_relate 来标记左侧列表是否滚动,在viewDidLoad和下面的代理中把_relate置为YES:

#pragma mark - UIScrollViewDelegate
//已经结束减速
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {_relate = YES;
}

  • 实现点击左侧单元格,右侧列表自动滚动到相应分区

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {if (tableView == _leftTableView) {_relate = NO;//选择该行,并自动滚动至列表中心区域[self.leftTableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];//右侧滚动至相应分区[self.rightTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.row] atScrollPosition:UITableViewScrollPositionTop animated:YES];}else {//取消选中[self.rightTableView deselectRowAtIndexPath:indexPath animated:NO];}
}

 

  • 实现滚动右侧列表,左侧列表自动选中相应分区标题

//分区头即将显示
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {if (_relate) {//获取显示在最顶部的cell的分区数NSInteger topCellSection = [[[tableView indexPathsForVisibleRows] firstObject] section];if (tableView == self.rightTableView) {//滚动该分区对应的标题至列表靠近中部区域[self.leftTableView selectRowAtIndexPath:[NSIndexPath indexPathForItem:topCellSection inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];}}
}//分区头已经结束显示
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section {if (_relate) {//获取显示在最顶部的cell的分区数NSInteger topCellSection = [[[tableView indexPathsForVisibleRows] firstObject] section];if (tableView == self.rightTableView) {//滚动该分区对应的标题至列表靠近中部区域[self.leftTableView selectRowAtIndexPath:[NSIndexPath indexPathForItem:topCellSection inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];}}
}

至此一个简单实用的经典双列表联动效果已经实现了!

Demo地址:

https://github.com/ly918/Demos

 

优化:


另外,我对其做了进一步的扩展优化,如加入购物车的动画,导航渐变等,效果图如下所示:

193435_9KOf_2279344.png

项目地址:

https://github.com/ly918/TakeawayList-ShoppingCart


转:https://my.oschina.net/Misayalvyuan/blog/893539



推荐阅读
  • 通过将常用的外部命令集成到VSCode中,可以提高开发效率。本文介绍如何在VSCode中配置和使用自定义的外部命令,从而简化命令执行过程。 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 更新vuex的数据为什么用mutation?
    更新vuex的数据为什么用mutation?,Go语言社区,Golang程序员人脉社 ... [详细]
  • Edition:theprobleminmyquestionwasIvetriedtofindmatrixSfromequation8butthisequati ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 解决Only fullscreen opaque activities can request orientation错误的方法
    本文介绍了在使用PictureSelectorLight第三方框架时遇到的Only fullscreen opaque activities can request orientation错误,并提供了一种有效的解决方案。 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • 在 `UITableViewController` 中采用简洁的平面样式布局时,可以通过优化代码实现单元格扩展至屏幕边缘的效果,同时确保节标题以分组样式呈现,从而提升用户体验和界面美观度。通过这种方式,可以更好地组织和展示列表内容,使其更加清晰和有序。 ... [详细]
  • 通过使用 `pandas` 库中的 `scatter_matrix` 函数,可以有效地绘制出多个特征之间的两两关系。该函数不仅能够生成散点图矩阵,还能通过参数如 `frame`、`alpha`、`c`、`figsize` 和 `ax` 等进行自定义设置,以满足不同的可视化需求。此外,`diagonal` 参数允许用户选择对角线上的图表类型,例如直方图或密度图,从而提供更多的数据洞察。 ... [详细]
  • com.sun.javadoc.PackageDoc.exceptions()方法的使用及代码示例 ... [详细]
author-avatar
我怎么了2602902235
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有