《小豪商城》项目总结
近期学习以及做了一个商城类项目。下面来进行整理。首先项目的整体演示入下.
项目的展示gif太大,放到github上做展示,点击这里即可观看
具体的项目截图如下
此项目,目前只是将大体的功能完成。包括框架的搭建,首页,分类页和购物车界面的完成。
剩下的界面,将在之后完善并提交到github上更新。包括首页的隐藏主页,通过长按悬浮按钮ImageButton进入。以及分类菜单里又添加的热卖界面和商品详情以及双RecyclerView的二级菜单。以及个人中心的Bmon登录界面还需要完成。
此项目用到的数据,是运行在tomcat服务器上的。需要的同学可以在这里下载。
服务器资源
至于怎么运行服务器资源,你只要将下载的资源压缩到Tomcat的Root目录下,然后运行Tomcat服务器即可(D:\Program Files\Tomcat\apache-tomcat-7.0.55\webapps\ROOT)PS:这是我的路径
首先是项目框架的搭建。
常见的底部菜单的实现方式:
常见的实现方式有:
1、TabHost+Activity:资源开销比较大,官方已经不推荐使用。
2、RadioButton(RadioGroup)+Fragment:实现起来比较麻烦。
3、FragmentTabHost+Fragment:实现也比较麻烦。和第二种差不多。
我在这个项目中使用的第二种,RadioButton+Fragment。每种的使用方式都差不多。
具体的逻辑可以看一下我的代码。
首页的布局很简单,一个帧布局给Fragment切换用的,然后是RadioGoup的组合。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
tools:context="com.zhonghao.shoppingmall.app.MainActivity">
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<RadioGroup
android:id="@+id/rg_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/home_bottom_parent_bg"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_home"
style="@style/MainButtonStyle"
android:drawableTop="@drawable/home_button_selector"
android:text="首页" />
<RadioButton
android:id="@+id/rb_type"
style="@style/MainButtonStyle"
android:drawableTop="@drawable/type_button_selector"
android:text="分类" />
<RadioButton
android:id="@+id/rb_community"
style="@style/MainButtonStyle"
android:drawableTop="@drawable/community_button_selector"
android:paddingTop="10dp"
android:text="发现" />
<RadioButton
android:id="@+id/rb_cart"
style="@style/MainButtonStyle"
android:drawableTop="@drawable/cart_button_selector"
android:text="购物车" />
<RadioButton
android:id="@+id/rb_user"
style="@style/MainButtonStyle"
android:drawableTop="@drawable/user_button_selector"
android:text="个人中心" />
</RadioGroup>
</LinearLayout>
MainActivity中的代码如下
public class MainActivity extends AppCompatActivity {
@BindView(R.id.frameLayout)
FrameLayout mFrameLayout;
@BindView(R.id.rb_home)
RadioButton mRbHome;
@BindView(R.id.rb_type)
RadioButton mRbType;
@BindView(R.id.rb_community)
RadioButton mRbCommunity;
@BindView(R.id.rb_cart)
RadioButton mRbCart;
@BindView(R.id.rb_user)
RadioButton mRbUser;
@BindView(R.id.rg_main)
RadioGroup mRgMain;
private List<BaseFragment> mFragments;
private int position = 0;
private BaseFragment mBaseFragment;//缓存的Fragment或者说是上次显示的Fragment
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initFragment();
initListener();
}
private void initFragment() {
mFragments = new ArrayList<>();
mFragments.add(new HomeFragment());
mFragments.add(new TypeFragment());
mFragments.add(new CommunityFragment());
mFragments.add(new ShoppingCartFragment());
mFragments.add(new UserFragment());
}
private void initListener() {
mRgMain.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
switch (checkedId) {
case R.id.rb_home:
position = 0;
break;
case R.id.rb_type:
position = 1;
break;
case R.id.rb_community:
position = 2;
break;
case R.id.rb_cart:
position = 3;
break;
case R.id.rb_user:
position = 4;
break;
}
BaseFragment curFragemnt = getFragment(position);
//第一个参数:上次显示的fragment
//第二个参数:当前正要显示的fragment
switchFragment(mBaseFragment, curFragemnt);
}
});
mRgMain.check(R.id.rb_home);//默认选中第一个按钮
}
private BaseFragment getFragment(int position) {
if (mFragments != null && mFragments.size() > 0) {
BaseFragment curFragment = mFragments.get(position);
return curFragment;
}
return null;
}
private void switchFragment(Fragment fromFragment, BaseFragment toFragemnt) {
if (mBaseFragment != toFragemnt) {
mBaseFragment = toFragemnt;
if (toFragemnt != null) {
FragmentTransaction fm = getSupportFragmentManager().beginTransaction();
//判断正要显示的Fragment是否添加
if (!toFragemnt.isAdded()) {
if (fromFragment != null) {
//隐藏当前fragment
fm.hide(fromFragment);
}
fm.add(R.id.frameLayout, toFragemnt).commit();
} else {
//隐藏当前Fragment
if (fromFragment != null) {
fm.hide(fromFragment);
}
fm.show(toFragemnt).commit();
}
}
}
}
}
首页主要是RecyclerView的多布局加载。其次有几个小的逻辑。一个是ImageButton的逻辑,点击实现返回顶部,这里用的是RecyclerView mRvHome.scrollToPosition(0);一个是首页的秒杀倒计时的实现。
因为在请求到的json数据里是这样的
提供了开始和结束时间,因此两者相减,然后利用handler不断发送消息,每次减少1秒,然后就可以实现了
/**
* 相差多少时间-毫秒
*/
private long dt = 0;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
dt = dt - 1000;
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
String time = formatter.format(new Date(dt));
tv_time_seckill.setText(time);
handler.removeMessages(0);
handler.sendEmptyMessageDelayed(0,1000);
if(dt <=0){
//把消息移除
handler.removeCallbacksAndMessages(null);
}
}
};
以及
//秒杀倒计时 -毫秒
dt = Integer.valueOf(seckill_info.getEnd_time()) - Integer.valueOf(seckill_info.getStart_time());
handler.sendEmptyMessageDelayed(0,1000);
一个是请求网络。这里请求网络用的是张鸿洋大神封装的OkHttpUtils库。之后,我也会重新将OkHttp自己封装一个库来使用。
解析数据用的阿里的fastJson。以及一个插件工具GsonFormat。这个插件工具将json数据导入,能自动生成fastJson使用的JavaBean.
分类界面主要也是数据的请求解析与展示。这个二级菜单使用的是listView+RecyclerView。
根据左边listview的点击position来加载对应右边的菜单的数据,然后传递给右边界面的adapter从而实现二级菜单。
不过具体的代码有些乱糟糟,之后我会用两个RecyclerView重新上线二级菜单。
此项目我感觉最难的逻辑就是购物车的实现。
首先商城APP中,我们需要把用户的添加到购物车的商品信息保存起来,其中每一条数据包含商品的基本信息(ID,图片,名字,介绍,价格等)以及用户添加的该商品的数量。
1、保存在云端(服务器)。如果我们的客户端有Android版本,IOS版本,Web版本等多版本的时候,这种方式可以进行不同版本的数据同步。因此,多版本下,必须使用这种方式存储购物车数据。
2、保存在客户端的系统的本地。
由于我们的APP开发只有Android版本,因此使用本地的方式存储购物车数据。
那么问题又来了,如果保存在本地,应该如何保存?
Android中常用的数据存储方式有:
1、使用数据库。
2、使用文件来存储。
3、使用SharePreference保存。
至于三种方式的区别这里不赘述,详细请去百度Android中常用的数据存储方式以及区别和使用。
我使用SharePreference存储购物车数据:通过把List中的Bean对象转换为JSON字符串数据来存起来,取出来的时候通过Gson重新把JSON转换为Bean对象。在内存中维护了两个数组,一个是我们常用的ArrayList,一个是稀疏数组SparseArray,ArrayList用于Adapter的展示,SparseArray主要用于存储(与JSON对象之间的转换)。由于我每一条Bean都是通过ID来区分的,因此一开始使用Map
package com.zhonghao.shoppingmall.shoppingcart.utils;
import android.content.Context;
import android.text.TextUtils;
import android.util.SparseArray;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.zhonghao.shoppingmall.app.MyAppliction;
import com.zhonghao.shoppingmall.home.bean.GoodsBean;
import com.zhonghao.shoppingmall.utils.CacheUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 项目名称:ShoppingMall
* 包名:com.zhonghao.shoppingmall.shoppingcart.utils
* 类描述:购物车数据存储类
* 创建人:小豪
* 创建时间:2017/7/3 20:29
*/
public class CartStorage {
private static final String JSON_CART = "json_cart";
private Context mContext;
private static CartStorage instance;
//SparseArray的性能优于Hashmap
private SparseArray<GoodsBean> mSparseArray;
public CartStorage(Context context) {
this.mContext = context;
mSparseArray = new SparseArray<>(100);
//把之前存储的数据读取
listToSparseArray();
}
/**
* 从本地读取的数据加入到SparseArray中
*/
private void listToSparseArray() {
List<GoodsBean> goodsBeanList = getAllData();
for (int i= 0; i<goodsBeanList.size();i++){
GoodsBean goodsBean = goodsBeanList.get(i);
mSparseArray.put(Integer.parseInt(goodsBean.getProduct_id()),goodsBean);
}
}
/**
* 获取本地所有的数据
*
* @return
*/
public List<GoodsBean> getAllData() {
List<GoodsBean> goodsBeanList = new ArrayList<>();
//1.从本地获取
String json = CacheUtils.getString(mContext, JSON_CART);
//2使用Gson转换成列表
if (!TextUtils.isEmpty(json)) {
//把String转成List
goodsBeanList = new Gson().fromJson(json, new TypeToken<List<GoodsBean>>() {
}.getType());
}
return goodsBeanList;
}
//得到购物车后实例
public static CartStorage getInstance(){
if (instance ==null){
instance = new CartStorage(MyAppliction.getContext());
}
return instance;
}
//添加数据
public void addData(GoodsBean goodsBean){
//1.添加到内存中SparseArray
//如果当前数据已经存在,就修改成number递增
GoodsBean tempData = mSparseArray.get(Integer.parseInt(goodsBean.getProduct_id()));
if(tempData != null){
//内存中有了这条数据
tempData.setNumber(tempData.getNumber()+1);
}else{
tempData = goodsBean;
tempData.setNumber(1);
}
//同步到内存中
mSparseArray.put(Integer.parseInt(tempData.getProduct_id()),tempData);
//2.同步到本地
saveLocal();
}
/**
* 删除数据
* @param goodsBean
*/
public void deleteData(GoodsBean goodsBean){
//1.内存中删除
mSparseArray.delete(Integer.parseInt(goodsBean.getProduct_id()));
//2.把内存的保持到本地
saveLocal();
}
/**
* 更新数据
* @param goodsBean
*/
public void updateData(GoodsBean goodsBean){
//1.内存中更新
mSparseArray.put(Integer.parseInt(goodsBean.getProduct_id()),goodsBean);
//2.同步到本地
saveLocal();
}
private void saveLocal() {
//1.SparseArray转换成List
List<GoodsBean> goodsBeanList = sparseToList();
//2.使用Gson把列表转换成String类型
String json = new Gson().toJson(goodsBeanList);
//3.把String数据保存
CacheUtils.putString(mContext,JSON_CART,json);
}
private List<GoodsBean> sparseToList() {
List<GoodsBean> goodsBeanList = new ArrayList<>();
for (int i=0;i<mSparseArray.size();i++){
GoodsBean goodsBean = mSparseArray.valueAt(i);
goodsBeanList.add(goodsBean);
}
return goodsBeanList;
}
}
之后在商品详情页中,对购物车的点击事件逻辑做一下
else if (v == btnGoodInfoAddcart) {
//添加购物车
cartProvider.addData(goods_bean);
// showPopwindow();
Toast.makeText(GoodsInfoActivity.this, "添加购物车",
Toast.LENGTH_SHORT).show();
}
接下来就是购物车的展示界面
首先是一个自定义的增加删除按钮,这个逻辑后期需要修改
package com.zhonghao.shoppingmall.shoppingcart.view;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.zhonghao.shoppingmall.R;
/**
* 项目名称:ShoppingMall
* 包名:com.zhonghao.shoppingmall.shoppingcart.view
* 类描述:自定义增加删除按钮
* 创建人:小豪
* 创建时间:2017/7/3 19:58
*/
public class AddSubView extends LinearLayout implements View.OnClickListener {
private final Context mContext;
private ImageView iv_sub;
private ImageView iv_add;
private TextView tv_value;
private int value = 1;
private int minValue = 1;
private int maxValue = 5;
public AddSubView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
//把布局文件实例化,并且加载到AddSubView类中
View.inflate(context, R.layout.add_sub_view,this);
iv_sub = (ImageView) findViewById(R.id.iv_sub);
tv_value = (TextView) findViewById(R.id.tv_value);
iv_add = (ImageView) findViewById(R.id.iv_add);
int value = getValue();
setValue(value);
//设置点击事件
iv_sub.setOnClickListener(this);
iv_add.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.iv_sub://减
subNumber();
break;
case R.id.iv_add://加
addNumebr();
break;
}
// Toast.makeText(mContext, "当前商品数=="+value, Toast.LENGTH_SHORT).show();
}
private void addNumebr() {
if(value < maxValue){
value ++;
}
setValue(value);
if(onNumberChangeListener !=null){
onNumberChangeListener.onNumberChange(value);
}
}
/**
* 减
*/
private void subNumber() {
if(value > minValue){
value --;
}
setValue(value);
if(onNumberChangeListener !=null){
onNumberChangeListener.onNumberChange(value);
}
}
public int getValue() {
String valueStr = tv_value.getText().toString().trim();
if(!TextUtils.isEmpty(valueStr)){
value = Integer.parseInt(valueStr) ;
}
return value;
}
public void setValue(int value) {
this.value = value;
tv_value.setText(value+"");
}
public int getMinValue() {
return minValue;
}
public void setMinValue(int minValue) {
this.minValue = minValue;
}
public int getMaxValue() {
return maxValue;
}
public void setMaxValue(int maxValue) {
this.maxValue = maxValue;
}
/**
* 当数量发生变化的时候回调
*/
public interface OnNumberChangeListener{
/**
* 当数据发生变化的时候回调
* @param value
*/
public void onNumberChange(int value);
}
private OnNumberChangeListener onNumberChangeListener;
/**
* 设置数量变化的监听
* @param onNumberChangeListener
*/
public void setOnNumberChangeListener(OnNumberChangeListener onNumberChangeListener) {
this.onNumberChangeListener = onNumberChangeListener;
}
}
购物车的布局界面就不放代码了。很多,可以下载我的源码看。主要的是购物车的逻辑代码
package com.zhonghao.shoppingmall.shoppingcart.fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.zhonghao.shoppingmall.R;
import com.zhonghao.shoppingmall.base.BaseFragment;
import com.zhonghao.shoppingmall.home.bean.GoodsBean;
import com.zhonghao.shoppingmall.shoppingcart.adapter.ShoppingCartAdapter;
import com.zhonghao.shoppingmall.shoppingcart.utils.CartStorage;
import java.util.List;
import static com.zhonghao.shoppingmall.R.id.ll_check_all;
import static com.zhonghao.shoppingmall.R.id.tv_shopcart_edit;
/**
* 项目名称:ShoppingMall
* 包名:com.zhonghao.shoppingmall.shoppingcart.fragment
* 类描述:
* 创建人:小豪
* 创建时间:2017/7/2 15:46
*/
public class ShoppingCartFragment extends BaseFragment implements View.OnClickListener {
private TextView tvShopcartEdit;
private RecyclerView recyclerview;
private LinearLayout llCheckAll;
private CheckBox checkboxAll;
private TextView tvShopcartTotal;
private Button btnCheckOut;
private LinearLayout llDelete;
private CheckBox cbAll;
private Button btnDelete;
private Button btnCollection;
private ImageView ivEmpty;
private TextView tvEmptyCartTobuy;
private LinearLayout ll_empty_shopcart;
private ShoppingCartAdapter adapter;
//编辑状态
private static final int ACTION_EDIT = 1;
//完成状态
private static final int ACTION_COMPLETE = 2;
@Override
public View initView() {
View view = View.inflate(mContext, R.layout.fragment_shoppingcart, null);
tvShopcartEdit = (TextView) view.findViewById(tv_shopcart_edit);
recyclerview = (RecyclerView) view.findViewById(R.id.recyclerview);
llCheckAll = (LinearLayout) view.findViewById(ll_check_all);
checkboxAll = (CheckBox) view.findViewById(R.id.checkbox_all);
tvShopcartTotal = (TextView) view.findViewById(R.id.tv_shopcart_total);
btnCheckOut = (Button) view.findViewById(R.id.btn_check_out);
llDelete = (LinearLayout) view.findViewById(R.id.ll_delete);
cbAll = (CheckBox) view.findViewById(R.id.cb_all);
btnDelete = (Button) view.findViewById(R.id.btn_delete);
btnCollection = (Button) view.findViewById(R.id.btn_collection);
ll_empty_shopcart = (LinearLayout) view.findViewById(R.id.ll_empty_shopcart);
ivEmpty = (ImageView) view.findViewById(R.id.iv_empty);
tvEmptyCartTobuy = (TextView) view.findViewById(R.id.tv_empty_cart_tobuy);
btnCheckOut.setOnClickListener(this);
btnDelete.setOnClickListener(this);
btnCollection.setOnClickListener(this);
initListener();
return view;
}
@Override
public void onResume() {
super.onResume();
showData();
}
private void showData() {
List<GoodsBean> goodsBeanList = CartStorage.getInstance().getAllData();
if (goodsBeanList != null && goodsBeanList.size() > 0) {
tvShopcartEdit.setVisibility(View.VISIBLE);
llCheckAll.setVisibility(View.VISIBLE);
//有数据
//把当没有数据显示的布局-隐藏
ll_empty_shopcart.setVisibility(View.GONE);
//设置适配器
adapter = new ShoppingCartAdapter(mContext, goodsBeanList, tvShopcartTotal, checkboxAll, cbAll);
recyclerview.setAdapter(adapter);
//设置布局管理器
recyclerview.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
} else {
//没有数据
//显示数据为空的布局
emptyShoppingCart();
}
}
private void initListener() {
//设置默认的编辑状态
tvShopcartEdit.setTag(ACTION_EDIT);
tvShopcartEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int action = (int) v.getTag();
if (action == ACTION_EDIT) {
//切换为完成状态
showDelete();
} else {
//切换成编辑状态
hideDelete();
}
}
});
}
private void hideDelete() {
//1.设置状态和文本-编辑
tvShopcartEdit.setTag(ACTION_EDIT);
tvShopcartEdit.setText("编辑");
//2.变成非勾选
if (adapter != null) {
adapter.checkAll_none(true);
adapter.checkAll();
adapter.showTotalPrice();
}
//3.删除视图显示
llDelete.setVisibility(View.GONE);
//4.结算视图隐藏
llCheckAll.setVisibility(View.VISIBLE);
}
private void showDelete() {
//1.设置状态和文本-完成
tvShopcartEdit.setTag(ACTION_COMPLETE);
tvShopcartEdit.setText("完成");
//2.变成非勾选
if (adapter != null) {
adapter.checkAll_none(false);
adapter.checkAll();
}
//3.删除视图显示
llDelete.setVisibility(View.VISIBLE);
//4.结算视图隐藏
llCheckAll.setVisibility(View.GONE);
}
@Override
public void onClick(View v) {
if (v == btnCheckOut) {
// Handle clicks for btnCheckOut
//结算
// pay(v);
} else if (v == btnDelete) {
// Handle clicks for btnDelete
//删除选中的
adapter.deleteData();
//校验状态
adapter.checkAll();
//数据大小为0
if(adapter.getItemCount()==0){
emptyShoppingCart();
}
} else if (v == btnCollection) {
// Handle clicks for btnCollection
}
}
private void emptyShoppingCart() {
ll_empty_shopcart.setVisibility(View.VISIBLE);
tvShopcartEdit.setVisibility(View.GONE);
llDelete.setVisibility(View.GONE);
}
}
以及购物车的适配器
package com.zhonghao.shoppingmall.shoppingcart.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.zhonghao.shoppingmall.R;
import com.zhonghao.shoppingmall.home.bean.GoodsBean;
import com.zhonghao.shoppingmall.shoppingcart.utils.CartStorage;
import com.zhonghao.shoppingmall.shoppingcart.view.AddSubView;
import com.zhonghao.shoppingmall.utils.Constants;
import java.util.List;
/**
* 项目名称:ShoppingMall
* 包名:com.zhonghao.shoppingmall.shoppingcart.adapter
* 类描述:
* 创建人:小豪
* 创建时间:2017/7/3 19:44
*/
public class ShoppingCartAdapter extends RecyclerView.Adapter<ShoppingCartAdapter.ViewHolder>{
private Context mContext;
private List<GoodsBean> datas;
private TextView tvShopcartTotal;
private CheckBox checkboxAll;
//完成状态下的删除CheckBox
private CheckBox cbAll;
public ShoppingCartAdapter(Context context, List<GoodsBean> datas) {
this.mContext = context;
this.datas = datas;
}
public ShoppingCartAdapter(Context context, List<GoodsBean> datas, TextView tvShopcartTotal, CheckBox checkboxAll, CheckBox cbAll) {
this.mContext = context;
this.datas = datas;
this.tvShopcartTotal = tvShopcartTotal;
this.checkboxAll = checkboxAll;
this.cbAll = cbAll;
showTotalPrice();
//设置点击事件
setListener();
//校验是否全选
checkAll();
}
/**
* 设置全选和非全选
* @param isCheck
*/
public void checkAll_none(boolean isCheck) {
if(datas != null && datas.size() >0){
for (int i=0;i<datas.size();i++){
GoodsBean goodsBean = datas.get(i);
goodsBean.setSelected(isCheck);
notifyItemChanged(i);
}
}
}
public void checkAll() {
if(datas != null && datas.size() >0){
int number = 0;
for (int i=0;i<datas.size();i++){
GoodsBean goodsBean = datas.get(i);
if(!goodsBean.isSelected()){
//非全选
checkboxAll.setChecked(false);
cbAll.setChecked(false);
}else{
//选中的
number ++;
}
}
if(number == datas.size()){
//全选
checkboxAll.setChecked(true);
cbAll.setChecked(true);
}
}else{
checkboxAll.setChecked(false);
cbAll.setChecked(false);
}
}
private void setListener() {
setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(int position) {
//1.根据位置找到对应的Bean对象
GoodsBean goodsBean = datas.get(position);
//2.设置取反状态
goodsBean.setSelected(!goodsBean.isSelected());
//3.刷新状态
notifyItemChanged(position);
//校验是否全选
checkAll();
//5.重新计算价格
showTotalPrice();
}
});
//CheckBox的点击事件
checkboxAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.得到状态
boolean isCheck = checkboxAll.isChecked();
//2.根据状态设置全选和非全选
checkAll_none(isCheck);
//3.计算总价格
showTotalPrice();
}
});
cbAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.得到状态
boolean isCheck = cbAll.isChecked();
//2.根据状态设置全选和非全选
checkAll_none(isCheck);
}
});
}
public void showTotalPrice() {
tvShopcartTotal.setText("合计:" +getTotalprice());
}
@Override
public ShoppingCartAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext,R.layout.item_shop_cart, null);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ShoppingCartAdapter.ViewHolder holder, final int position) {
//1.根据位置到的对应的Bean对象
final GoodsBean goodsBean = datas.get(position);
//2设置数据
holder.cb_gov.setChecked(goodsBean.isSelected());
Glide.with(mContext).load(Constants.BASE_URL_IMAGE + goodsBean.getFigure()).into(holder.iv_gov);
holder.tv_desc_gov.setText(goodsBean.getName());
holder.tv_price_gov.setText("¥" + goodsBean.getCover_price());
holder.ddSubView.setValue(goodsBean.getNumber());
holder.ddSubView.setMinValue(1);
holder.ddSubView.setMaxValue(8);
//设置商品数量的变化
holder.ddSubView.setOnNumberChangeListener(new AddSubView.OnNumberChangeListener() {
@Override
public void onNumberChange(int value) {
//1当前列表内存中
goodsBean.setNumber(value);
//2本地更新
CartStorage.getInstance().updateData(goodsBean);
//3.刷新适配器
notifyItemChanged(position);
//4.再次计算价格
showTotalPrice();
}
});
}
@Override
public int getItemCount() {
return datas.size();
}
/**
* 计算总价格
* @return
*/
private double getTotalprice() {
double totalPrice=0.0;
if (datas!= null&&datas.size()>0){
for (int i =0 ;i<datas.size();i++){
GoodsBean goodsBean = datas.get(i);
if (goodsBean.isSelected()){
totalPrice = totalPrice + Double.valueOf(goodsBean.getNumber())*Double.valueOf(goodsBean.getCover_price());
}
}
}
return totalPrice;
}
public void deleteData() {
if(datas != null && datas.size() >0){
for (int i=0;i<datas.size();i++){
//删除选中的
GoodsBean goodsBean = datas.get(i);
if(goodsBean.isSelected()){
//内存-把移除
datas.remove(goodsBean);
//保持到本地
CartStorage.getInstance().deleteData(goodsBean);
//刷新
notifyItemRemoved(i);
i--;
}
}
}
}
class ViewHolder extends RecyclerView.ViewHolder{
private CheckBox cb_gov;
private ImageView iv_gov;
private TextView tv_desc_gov;
private TextView tv_price_gov;
private AddSubView ddSubView;
public ViewHolder(View itemView) {
super(itemView);
cb_gov = (CheckBox) itemView.findViewById(R.id.cb_gov);
iv_gov = (ImageView) itemView.findViewById(R.id.iv_gov);
tv_desc_gov = (TextView) itemView.findViewById(R.id.tv_desc_gov);
tv_price_gov = (TextView) itemView.findViewById(R.id.tv_price_gov);
ddSubView = (AddSubView) itemView.findViewById(R.id.ddSubView);
//设置item的点击事件
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(onItemClickListener != null){
onItemClickListener.onItemClick(getLayoutPosition());
}
}
});
}
}
public interface OnItemClickListener{
/**
* 当点击某条的时候被回调
* @param position
*/
public void onItemClick( int position);
}
private OnItemClickListener onItemClickListener;
/**
* 设置item的监听
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}
在我的自定义增加删除按钮的代码中,和适配器的代码中都自己定义了一个接口用来给外部的点击事件回调。
大体上,主要叙述的逻辑就是这些。难点就在购物车的实现上。
因为面临秋招,暑假时间用来复习基础知识,包括Java,Android,数据结构等。所以每天敲码的时间只有下午。
接下来我会再利用一周的时间,把以上需要优化完善的功能全部实现,把剩下未完成的界面也全部实现。