使用 RecyclerView 做点餐列表联动页面

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。

最近刚换了工作,来到一家做了11年餐饮软件管理的公司,开发平板端点餐安卓端原生app。因为之前一直没做过类似的软件,对于我来说是一个全新的开始,所以打算写博客记录下来我从头开发的整个过程。

平板设置横屏属性就可以横屏在平板上显示,不用担心切换横竖屏会导致activity的生命周期改变。代码如下:

android:launchMode="singleTask" android:screenOrientation="landscape"

之后就开始做点餐界面,因为主界面就是专门用来点餐的,所以直接开始做点餐界面。产品经理说整个app是不需要联网就可以进行的,所有的资料是从后台下载下来之后存储下来,然后再取出来。之前一直没涉及到数据库的知识,所以这也是我学习的重点。

最先开始呢就是先做二级列表菜单页面,我用的是 RecyclerView ,很多知识可以从鸿洋的博客学习,我做的这个很大程度上也是从上面学习的
http://blog.csdn.net/lmj623565791/article/details/45059587
还有一部分是从
http://blog.csdn.net/w804518214/article/details/51570975
上面学习的,不过很大程度上改进了,根据我的需求在他的基础上做了很多改变。

效果图来看不复杂内容并没多少,值得介绍一下的知识点也就下面几个吧

  • 左右列表滑动时联动
  • 添加商品时的抛物线动画
  • 底部弹出购物车清单
  • 数据的同步

左右列表联动

联动主要有两个效果
- 左侧列表点击选择分类,右侧列表滑动到对应分类
- 右侧列表滑动过程中左侧列表高亮的分类跟随变化

第一个效果简单,左侧列表item添加点击事件,事件中调用右侧列表的setSelection(int positon) 方法。

第二个效果要给右侧列表添加ScrollListener,根据列表中显示的第一条数据设置左侧选中的分类

listView.setOnScrollListener(new RecyclerView.OnScrollListener(){public void onScrollStateChanged(RecyclerView view, int scrollState) {}public void onScrolled(RecyclerView view, int firstVisibleItem, int visibleItemCount) {//根据firstVisibleItem获取分类ID,根据分类id获取左侧要选中的位置GoodsItem item = dataList.get(firstVisibleItem);if(typeAdapter.selectTypeId != item.typeId) {typeAdapter.selectTypeId = item.typeId;typeAdapter.notifyDataSetChanged();//左侧列表是个RecyclerView 所以使用smoothScrollToPosition(int position) 使当对应position的item可以滚动显示出来rvType.smoothScrollToPosition(getSelectedGroupPosition(item.typeId));}}});

添加商品的动画

添加商品一共有三个动画
- 当商品从0到1 旋转左移显示出减号按钮
- 当商品从1到0 减号按钮旋转右移消失
- 添加商品时抛物线动画添加到购物车图标

前两个动画很简单可以分解成三个补间动画 旋转、平移、透明度。

/*** 点击加号显示减号的动画* @return*/private Animation getShowAnimation(){AnimationSet set = new AnimationSet(true);RotateAnimation rotate = new RotateAnimation(0,720,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);set.addAnimation(rotate);TranslateAnimation translate = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,2f,TranslateAnimation.RELATIVE_TO_SELF,0,TranslateAnimation.RELATIVE_TO_SELF,0,TranslateAnimation.RELATIVE_TO_SELF,0);set.addAnimation(translate);AlphaAnimation alpha = new AlphaAnimation(0,1);set.addAnimation(alpha);set.setDuration(500);return set;}/*** 隐藏减号的动画* @return*/private Animation getHiddenAnimation(){AnimationSet set = new AnimationSet(true);RotateAnimation rotate = new RotateAnimation(0,720,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);set.addAnimation(rotate);TranslateAnimation translate = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,0,TranslateAnimation.RELATIVE_TO_SELF,2f,TranslateAnimation.RELATIVE_TO_SELF,0,TranslateAnimation.RELATIVE_TO_SELF,0);set.addAnimation(translate);AlphaAnimation alpha = new AlphaAnimation(1,0);set.addAnimation(alpha);set.setDuration(500);return set;}}

抛物线动画和上面的差不多可以分解成两个平移动画,不过两个平移动画的差值器一个线性一个加速而已,因为动画界面跨度比较大所以需要在根部局内写,不能写在列表的item中(这样会显示不全)。
代码中的anim_mask_layout 即为整个布局文件的根布局,这里是一个RelativeLayout

实现过程
1、首先点击加号图标,拿到控件在屏幕上的绝对坐标,回调activity显示动画

 int[] loc = new int[2];v.getLocationInWindow(loc);activity.playAnimation(loc);

2、创建动画的控件并添加到根部局并在动画结束后移除动画view

public void playAnimation(int[] start_location){ImageView img = new ImageView(this);img.setImageResource(R.drawable.button_add);setAnim(img,start_location);}//创建动画 平移动画直接传递偏移量 private Animation createAnim(int startX,int startY){int[] des = new int[2];imgCart.getLocationInWindow(des);AnimationSet set = new AnimationSet(false);Animation translationX = new TranslateAnimation(0, des[0]-startX, 0, 0);//线性插值器 默认就是线性translationX.setInterpolator(new LinearInterpolator());Animation translationY = new TranslateAnimation(0, 0, 0, des[1]-startY);//设置加速插值器translationY.setInterpolator(new AccelerateInterpolator());Animation alpha = new AlphaAnimation(1,0.5f);set.addAnimation(translationX);set.addAnimation(translationY);set.addAnimation(alpha);set.setDuration(500);return set;}//计算动画view在根部局中的坐标 添加到根部局中private void addViewToAnimLayout(final ViewGroup vg, final View view,int[] location) {int x = location[0];int y = location[1];int[] loc = new int[2];vg.getLocationInWindow(loc);view.setX(x);view.setY(y-loc[1]);vg.addView(view);}//设置动画结束移除动画view private void setAnim(final View v, int[] start_location) {addViewToAnimLayout(anim_mask_layout, v, start_location);Animation set = createAnim(start_location[0],start_location[1]);set.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(final Animation animation) {//直接remove可能会因为界面仍在绘制中成而报错mHanlder.postDelayed(new Runnable() {@Overridepublic void run() {anim_mask_layout.removeView(v);}},100);}@Overridepublic void onAnimationRepeat(Animation animation) {}});v.startAnimation(set);}

底部弹出购物车清单

底部弹出的效果大家一定都很熟悉了,几回每个项目中都会用的到,官方没有提供简单的控件实现,一般都需要自己写,不过要做到简单流畅,便于移植推荐使用第三方库,这里向大家推荐一个

bottomsheet

集成简单,效果多样这里简单介绍一下使用方法

集成
 compile 'com.flipboard:bottomsheet-core:1.5.1'

xml中使用BottomSheetLayout包裹弹出view时候的背景布局,BottomSheetLayout继承自帧布局

<com.flipboard.bottomsheet.BottomSheetLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/bottomSheetLayout"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.widget.RecyclerViewandroid:layout_width="100dp"android:id="@+id/typeRecyclerView"android:layout_height="match_parent"></android.support.v7.widget.RecyclerView><se.emilsjolander.stickylistheaders.StickyListHeadersListViewandroid:layout_width="match_parent"android:background="#fff"android:id="@+id/itemListView"android:layout_height="match_parent"></se.emilsjolander.stickylistheaders.StickyListHeadersListView></LinearLayout>
</com.flipboard.bottomsheet.BottomSheetLayout>

代码中使用很简单

 //弹出View  bottomSheet即是要弹出的viewbottomSheetLayout.showWithSheetView(bottomSheet);//代码隐藏view (点击弹出view以外的地方可以隐藏弹出的view,向下滑动也可以)bottomSheetLayout.dismissSheet();

数据的同步

同步数据,控制界面刷新应该是新手最容易绕弯的地方了,其实只要仔细一点也不难,这里简单提供一种思路(并不一定适合你的项目).

 //商品列表private ArrayList<GoodsItem> dataList;//分类列表private ArrayList<GoodsItem> typeList;//已选择的商品private SparseArray<GoodsItem> selectedList;//用于记录每个分组选择的数目private SparseIntArray groupSelect;

SparseArray这个类其实就是 HashMap< Integer,Object >

不过SparseArray既可以根据key查找Value,也可以根据位置查找value,性能比HashMap高,是官方推荐的替代类,
同样SparseIntArray 其实是HashMap< Integer,Integer> 的替代者。

Activity里实现了下面几个方法,用于数据统一管理
列表中显示的商品购买数量统一从activity获取,商品的加减统一调用Activity的方法然后notifiDatasetChanged,由于代码不少具体的还是看源码吧

 /*** Item代表商品的购买数量加一* @param item* @param refreshGoodList 是否刷新商品list*/public void add(GoodsItem item,boolean refreshGoodList){int groupCount = groupSelect.get(item.typeId);if(groupCount==0){groupSelect.append(item.typeId,1);}else{groupSelect.append(item.typeId,++groupCount);}GoodsItem temp = selectedList.get(item.id);if(temp==null){item.count=1;selectedList.append(item.id,item);}else{temp.count++;}update(refreshGoodList);}/*** Item商品的购买数量减一* @param item* @param refreshGoodList 是否刷新商品list*/public void remove(GoodsItem item,boolean refreshGoodList){int groupCount = groupSelect.get(item.typeId);if(groupCount==1){groupSelect.delete(item.typeId);}else if(groupCount>1){groupSelect.append(item.typeId,--groupCount);}GoodsItem temp = selectedList.get(item.id);if(temp!=null){if(temp.count<2){selectedList.remove(item.id);}else{item.count--;}}update(refreshGoodList);}/*** 刷新界面 总价、购买数量等* @param refreshGoodList 是否刷新商品list*/private void update(boolean refreshGoodList){...}//根据商品id获取当前商品的采购数量public int getSelectedItemCountById(int id){GoodsItem temp = selectedList.get(id);if(temp==null){return 0;}return temp.count;}//根据类别Id获取属于当前类别的数量public int getSelectedGroupCountByTypeId(int typeId){return groupSelect.get(typeId);}

这个页面改动的地方不是很多,但是我还是做了好几天的时间才做出来,左右列表都是用的 RecyclerView 做的,需要匹配的地方有很。

使用 RecyclerView 做点餐列表联动页面相关推荐

  1. RecyclerView双列表联动

    双列表联动效果如下: 以上,是博主根据鸿洋大神的玩Android开放的API做的一个客户端,其中导航界面使用了双列表联动来展示数据. 一.前期基础知识储备 1.使用强大的开源项目BRVAH装载两个列表 ...

  2. Android之两级联动点餐列表

    文章目录 前言 一.效果图 二.实现步骤 1.相关layout 2.相关adapter 3.自定义view 4.activity实现 总结 前言 此功能为两个listview相互联动,左边listvi ...

  3. 【4003】通过html+css做一个图片列表的静态页面。

    [4003]通过html+css做一个图片列表的静态页面. 学习目标: [ 1]学习前端第三天掌握 html与css(基础选择器,有.无序列表相关)入门知识,梳理今天的学习知识点: [ 2]通过已学知 ...

  4. android纵向列表菜单栏实现,RecyclerView实现常见的列表菜单

    在很多地方我们都会用到纵向列表样式的菜单,比如微信首页的我.发现页面,微博的首页的我页面,QQ的动态页面等等等等,大多数的应用中都会存在这样的页面.我们怎样实现这种页面比较好呢? 布局方案 完成这样的 ...

  5. 安卓开发之用RecyclerView做陈列式布局(仿小红书首页/淘宝商品浏览)

    安卓开发之用RecyclerView做陈列式布局 一.使用RecyclerView要先导入recyclerview-v7库 二.在layout文件夹内,新建一个xml文件,编写你要展示的item的样式 ...

  6. Android股票列表联动

    使用ScrollerView+RecycleView实现股票列表联动效果:一个可以拿来可以直接使用的解决方案,而且滑动流畅,带标题栏悬浮功能,支持整行的点击效果,支持长安事件: 效果如下图所示: 实现 ...

  7. RecyclerView滚动指定条目并在页面中居中

    RecyclerView滚动指定条目并在页面中居中 内容提要 本次的需求是通过指定position来控制条目滚动,并且要滚动到指定到中间的位置. 下面先上图,看看是不是你要 如下介绍主要的步骤 带着问 ...

  8. 小程序点餐系统——点餐列表页(未讲解完)

    文章目录 点餐列表(※) 代码 页面设计 页面样式 页面逻辑 点餐列表(※) 代码 页面设计 页面分为四部分 顶部:折扣信息区 左侧:菜单总览 右侧:菜单详细列表栏 底部:购物操作 顶部: 很简单 & ...

  9. 视频列表html页面,vue + video.js实现视频列表页(多个视频)

    vue + video.js实现视频列表页 vue项目中做一个视频列表页,本来用原生video标签来实现,由于考虑到手机浏览器兼容问题,找了很多插件,最后决定用video.js这个插件来实现.Vide ...

最新文章

  1. 事务隔离性与隔离级别
  2. LINUX分区空间扩容操作
  3. 大数据NoSQL技术之Couchbase Server数据库详解
  4. PHP(二)——HTML基础
  5. mysql 时间 本周 本月_mysql查询当天、本周、上周、本月、上月信息
  6. 三星w系列vip服务器,高端人士候机专属特权 三星W2017一张行走的VIP卡
  7. MailMail正式发布!注册码免费发放活动开启!(已结束~~不要再回复咧~)
  8. python实现求解字符串集的最长公共前缀
  9. 对c语言编辑的贪吃蛇的报告,C语言贪吃蛇实验报告材料.doc
  10. 高中计算机教学设计案例分析,高一年级信息技术教学设计(案例)
  11. 【真人手势动画制作软件】万彩手影大师教程 | 预览、保存及发布视频
  12. 免费https ssl证书freessl.org的申请及配置
  13. 面渣逆袭:Java并发六十问,快来看看你会多少道
  14. 小米10青春版刷鸿蒙,功能齐全也不行!小米10青春版现已跌至新低价,高刷已成趋势?...
  15. 基于SVG的绘制多边形jQuery插件
  16. python获取交换机信息
  17. 腾讯(大连)研发一面-20190620
  18. linux之cp/scp命令+scp命令详解---远程拷贝
  19. 【mysql】mysql 常用建表语句
  20. Spike探针-敏捷

热门文章

  1. Navicat mysql添加外键
  2. python批处理将图片进行放大
  3. 【实践】【买玫瑰花】
  4. NIO详解(六):Java堆外内存
  5. fofa批量获取致远oa【py脚本】
  6. 极速搭建周立功IMX283A ARM Linux开发环境(1)
  7. [原创]Woden的艰辛找工历程
  8. 微信扫描二维码关注公众号并成为下级
  9. 录音文件下载_办公软件推荐及使用方法?试试“录音转文字助手”手机APP
  10. [图像]Canny检测的Matlab实现(含代码)