Android仿外卖购物车功能

先看看效果图:

知识点分析

效果图来看不复杂内容并没多少,值得介绍一下的知识点也就下面几个吧
- 列表标题悬停
- 左右列表滑动时联动
- 添加商品时的抛物线动画
- 底部弹出购物车清单
- 数据的同步

另外就是实现效果的时候可能会遇到的几个坑。。。

布局很简单直接进入代码

1:列表标题悬停

现在做项目列表什么的基本抛弃了ListView改用RecyclerView,上篇博客中的标题悬停也是使用了一个RecyclerView的开源项目sticky-headers-recyclerview,不过写这个demo的时候遇到了两个坑

1)、sticky-headers-recyclerview做悬停标题的时候scrollToPosition(int position)方法滚动的位置不准确。
2)、当布局复杂点的时候 如果RecyclerView的宽度自适应或者使用权重百分比之类可能会导致header显示空白。

并且该开源项目作者已经停止维护,所以这次又换回了StickyListHeadersListView。

需要购物车Demo的很多都是新手,这里简单介绍下StickyListHeadersListView的使用

1)、AS引用 gradle文件dependencies内添加
    compile 'se.emilsjolander:stickylistheaders:2.7.0'

2)、xml文件中使用StickyListHeadersListView代替ListView

<se.emilsjolander.stickylistheaders.StickyListHeadersListView android:layout_width="match_parent" android:background="#fff" android:id="@+id/itemListView" android:layout_height="match_parent"> </se.emilsjolander.stickylistheaders.StickyListHeadersListView>

3)、Adapter继承BaseAdapter和接口StickyListHeadersAdapter
StickyListHeadersAdapter接口包括两个方法

View getHeaderView(int position, View convertView, ViewGroup parent); long getHeaderId(int position);

代码中使用和ListView一样,下面是几个特有的方法,看方法名也很容易理解用途

public void setAreHeadersSticky(boolean areHeadersSticky); public boolean areHeadersSticky(); public void setOnHeaderClickListener(OnHeaderClickListener listener); public interface OnHeaderClickListener { public void onHeaderClick(StickyListHeadersListView l, View header, int itemPosition, long headerId, boolean currentlySticky); } public void setOnStickyHeaderChangedListener(OnStickyHeaderChangedListener listener); public interface OnStickyHeaderChangedListener { void onStickyHeaderChanged(StickyListHeadersListView l, View header, int itemPosition, long headerId); } public View getListChildAt(int index); public int getListChildCount();

2:左右列表联动

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

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

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

listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //根据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(int position)(getSelectedGroupPosition(item.typeId)); } } });

3:添加商品的动画

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

前两个动画很简单可以分解成三个补间动画 旋转、平移、透明度。
可以用xml完成,也可以代码设置,不过有个小坑要注意一下 旋转动画一定要在平移动画前面,否则就不是滚动平移了,而是乱跳。。。

这里贴一下动画的代码设置方法

//显示减号的动画 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; } //隐藏减号的动画 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; } //执行动画 只需给对应控件setAnimation然后调用setVisibility方法即可 { .... tvMinus.setAnimation(getHiddenAnimation()); tvMinus.setVisibility(View.GONE); }

抛物线动画和上面的差不多可以分解成两个平移动画,不过两个平移动画的差值器一个线性一个加速而已,因为动画界面跨度比较大所以需要在根部局内写,不能写在列表的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() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(final Animation animation) { //直接remove可能会因为界面仍在绘制中成而报错 mHanlder.postDelayed(new Runnable() { @Override public void run() { anim_mask_layout.removeView(v); } },100); } @Override public void onAnimationRepeat(Animation animation) { } }); v.startAnimation(set); }

4:底部弹出购物车清单

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

bottomsheet

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

集成
compile 'com.flipboard:bottomsheet-core:1.5.1'
使用
xml中使用BottomSheetLayout包裹弹出view时候的背景布局,BottomSheetLayout继承自帧布局:

<com.flipboard.bottomsheet.BottomSheetLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/bottomSheetLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:layout_width="100dp" android:id="@+id/typeRecyclerView" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> <se.emilsjolander.stickylistheaders.StickyListHeadersListView android: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即是要弹出的view bottomSheetLayout.showWithSheetView(bottomSheet); //代码隐藏view (点击弹出view以外的地方可以隐藏弹出的view,向下滑动也可以) bottomSheetLayout.dismissSheet();

5:数据的同步

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

//商品列表 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); }

具体逻辑还是看代码吧,也许有更简单的实现。。。

Demo下载地址,下载到的文件是个AS module,你可以在自己新建的工程中Import Module.

源码下载:Android仿外卖购物车功能

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-03 08:16:07

Android仿外卖购物车功能的相关文章

Android仿外卖购物车功能_Android

先看看效果图: 知识点分析 效果图来看不复杂内容并没多少,值得介绍一下的知识点也就下面几个吧 - 列表标题悬停 - 左右列表滑动时联动 - 添加商品时的抛物线动画 - 底部弹出购物车清单 - 数据的同步 另外就是实现效果的时候可能会遇到的几个坑... 布局很简单直接进入代码 1:列表标题悬停 现在做项目列表什么的基本抛弃了ListView改用RecyclerView,上篇博客中的标题悬停也是使用了一个RecyclerView的开源项目sticky-headers-recyclerview,不过写

Android仿微信@好友功能 输入@跳转、删除整块

最近在做聊天功能的时候,有一个需求是仿照微信做@好友的功能,本来以为挺简单,但是做到这块的时候,发现和想象的有点不一样,什么整块删除,块可编辑,总之,加个@的功能很简单,但是要做和微信的一样还是费了一些功夫,下面是一个demo仅供参考,防止遗忘 先上个效果图 就是这么个功能 1. 分析需求 输入@跳转到联系人界面,选中一个或者多个好友返回到当前界面 按退格键删除整块内容 块内的内容可编辑,编辑完了之后将不附带@功能,只是单纯的文字 2. 开始编码 既然是文本输入首先继承EditText自定义一个

Android仿QQ附近的人搜索展示功能_Android

 1.概述 老规矩,先上图 原装货(就不录制gif了,大家可以自己在Q群助手开启共享地理位置,返回群聊天页面就看到看到附近的人): 看起来还是挺像的吧. 通过观察,我们可以获取得到如下关系 1.下面展示列表我们可以使用ViewPager来实现(当然如果你不觉得麻烦,你也可以用HorizontalScrollView来试试) 2.上面的扫描图,肯定是个ViewGroup(因为里面的小圆点是可以点击的,如果是View的话,对于这些小圆点的位置的判断,以及对小圆点缩放动画的处理都会超级麻烦,难以实现)

Android实现购物车功能_Android

最近看了一些淘宝购物车的demo,于是也写了一个. 效果图如下: 主要代码如下: actvity中的代码: public class ShoppingCartActivity extends BaseActivity { private List<Test> data; private ListView mListView; private ShoppingCartAdapter adapter; private RelativeLayout rlRefresh; private TextVi

购物车功能-关于android中购物车的功能实现

问题描述 关于android中购物车的功能实现 在页面里将物品加入购物车,怎么才能将数据传入购物车里,使购物车物品增多呢? 解决方案 http://www.cnblogs.com/hongten/archive/2012/12/26/hongten_cookies.html 之前没有接触过购物车的东东,也不知道购物车应该怎么做,所以在查询了很多资料,总结一下购物车的功能实现. 查询的资料,找到三种方法: 1.用cookie实现购物车: 2.用session实现购物车: 3.用cookie和数据库

Android仿UC浏览器左右上下滚动功能_Android

本文要解决在侧滑菜单右边加个文本框,并能实现文本的上下滑动和菜单的左右滚动.这里推荐可以好好看看android的触摸事件的分发机制,这里我就不详细讲了,我只讲讲这个应用.要实现的功能就像UC浏览器(或其它手机浏览器)的左右滚动,切换网页,上下滚动,拖动内容. 本文的效果:   一.功能要求与实现1.功能要求:(1)手指一开始按着屏幕左右移动时,只能左右滚动菜单,如果这时手指一直按着,而且上下移动了,那么菜单显示部分保持不变,但文本框也不上下移动!                       (2

Android仿微信发表说说实现拍照、多图上传功能_Android

本文实例为大家分享了Android仿微信发表说说.心情功能,供大家参考,具体内容如下 既能实现拍照,选图库,多图案上传的案例,目前好多App都有类似微信朋友圈的功能,能过发表说说等附带图片上传.下面的就是实现该功能的过程:大家还没有看过Android Retrofit 2.0框架上传图片解决方案这篇文章,在看今天的就很容易,接在本项目中用到了一个library:photopicker,封装了图片的选择功能,是否选相机,还有选中图片后可以查看图片的功能.   一. 首先:将photopicker到

Android 仿微信朋友圈点赞和评论弹出框功能_Android

贡献/下载源码:https://github.com/mmlovesyy/PopupWindowDemo 本文简单模仿微信朋友圈的点赞和评论弹出框,布局等细节请忽略,着重实现弹出框.发评论,及弹出位置的控制. 1. 微信弹出框 微信朋友圈的点赞和评论功能,有2个组成部分: 点击左下角的"更多"按钮,弹出对话框: 点击评论,弹出输入框,添加评论并在页面中实时显示:   微信朋友圈点赞和评论功能 2. 实际效果 本文将建一个 ListView,在其 Item 中简单模仿微信的布局,然后着重

Android仿微信滑动弹出编辑、删除菜单效果、增加下拉刷新功能_Android

如何为不同的list item呈现不同的菜单,本文实例就为大家介绍了Android仿微信或QQ滑动弹出编辑.删除菜单效果.增加下拉刷新等功能的实现,分享给大家供大家参考,具体内容如下 效果图: 1. 下载开源项目,并将其中的liberary导入到自己的项目中: 2. 使用SwipeMenuListView代替ListView,在页面中布局: <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefresh