前言:
RecyclerView是android 最常见的列表控件,它现在几乎已经代替了listVIew和GridView的使用,RecyclerView自带强大的功能,实现多种样式,使用更加简单,封装也很容易,相对于listIView,RecyclerView没有自己的item点击事件,需要开发人员自行通过接口回调来实现点击事件,在近期工作不忙时,我查阅了一些开源的商城项目,写了一套很全面的商城app的购物车功能的demo。
闲话少说先上运行图:
就上传这三张图,了解下大致功能。
1.项目搭配代码进行分析(这里只提供主要方法,详细的demo最下方分享)
1),个数的增加与减少实现:
自定义一个类,继承LinearLayoutb (AddSubView)
对加减按钮进行编写
通过回调方法进行回调
响应回调方法
2)最外层布局
<?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="#fff"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#fff">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="30dp"
android:layout_weight="1"
android:text="购物车"
android:textColor="#303235"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_shopcart_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="编辑"
android:textColor="#303235" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="#eeee" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp"
android:background="#eee" />
<LinearLayout
android:id="@+id/ll_check_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:orientation="horizontal"
android:visibility="visible">
<CheckBox
android:id="@+id/checkbox_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:button="@null"
android:drawableLeft="@drawable/checkbox_selector"
android:drawablePadding="10dp"
android:padding="10dp"
android:paddingLeft="0dp"
android:text="全选"
android:textColor="#303235"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="合计:"
android:textColor="#303235"
android:textSize="15sp" />
<TextView
android:id="@+id/tv_shopcart_total"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp"
android:text="¥0.00"
android:textColor="#ed3f3f"
android:textSize="15sp" />
<Button
android:id="@+id/btn_check_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ed3f3f"
android:text="去结算"
android:textColor="#fff" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:orientation="horizontal"
android:padding="5dp"
android:visibility="gone">
<CheckBox
android:id="@+id/cb_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_weight="1"
android:button="@null"
android:drawableLeft="@drawable/checkbox_selector"
android:drawablePadding="10dp"
android:padding="10dp"
android:paddingLeft="0dp"
android:text="全选"
android:textColor="#303235"
android:textSize="15sp" />
<Button
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:background="@drawable/words"
android:text="删除"
android:textColor="#303235"
android:textSize="15sp" />
<Button
android:id="@+id/btn_collection"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_marginLeft="15dp"
android:background="@drawable/wordsred"
android:text="收藏"
android:textColor="#ed3f3f"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
<include layout="@layout/empty_cart" />
</FrameLayout>
</LinearLayout>
3)购物车的activity
public class MainActivity extends Activity 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 btnColletion;
private LinearLayout llViewNo;
//编辑状态
private static final int ACTION_EDIT = 1;
//完成状态
private static final int ACTION_COMPLETE = 2;
private ShoppingCartAdapter shoppingCartAdapter;
List<GoodsBean> allData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
allData = new ArrayList<>();
initUI();
}
private void initUI() {
tvShopcartEdit = findViewById(R.id.tv_shopcart_edit);
recyclerview = findViewById(R.id.recyclerview);
llCheckAll = findViewById(R.id.ll_check_all);
checkboxAll = findViewById(R.id.checkbox_all);
tvShopcartTotal = findViewById(R.id.tv_shopcart_total);
btnCheckOut = findViewById(R.id.btn_check_out);
llDelete = findViewById(R.id.ll_delete);
cbAll = findViewById(R.id.cb_all);
btnDelete = findViewById(R.id.btn_delete);
btnColletion = findViewById(R.id.btn_collection);
//没有数据的布局
llViewNo = findViewById(R.id.ll_empty_shopcart);
btnCheckOut.setOnClickListener(this);
btnDelete.setOnClickListener(this);
btnColletion.setOnClickListener(this);
inistener();
}
@Override
protected void onResume() {
super.onResume();
showData();
}
private void showData() {
GoodsBean goodsBean1 = new GoodsBean();
goodsBean1.setCover_price("159");
goodsBean1.setFigure("http://img3.imgtn.bdimg.com/it/u=344195214,1892239641&fm=26&gp=0.jpg");
goodsBean1.setName("时尚男士韩版T血,挥泪大甩卖");
goodsBean1.setNumber(0);
GoodsBean goodsBean2 = new GoodsBean();
goodsBean2.setCover_price("1599.00");
goodsBean2.setFigure("http://img3.imgtn.bdimg.com/it/u=2757819565,4220707122&fm=26&gp=0.jpg");
goodsBean2.setName("时尚女性");
goodsBean2.setNumber(0);
GoodsBean goodsBean3 = new GoodsBean();
goodsBean3.setCover_price("1259.00");
goodsBean3.setFigure("http://img3.imgtn.bdimg.com/it/u=344195214,1892239641&fm=26&gp=0.jpg");
goodsBean3.setName("时尚男士韩版T血,挥泪大甩卖");
goodsBean3.setNumber(1);
GoodsBean goodsBean4 = new GoodsBean();
goodsBean4.setCover_price("9.99");
goodsBean4.setFigure("http://img3.imgtn.bdimg.com/it/u=902518220,2743667191&fm=26&gp=0.jpg");
goodsBean4.setName("时尚男士韩版T血,挥泪大甩卖");
goodsBean4.setNumber(0);
allData.add(goodsBean1);
allData.add(goodsBean2);
allData.add(goodsBean3);
allData.add(goodsBean4);
if(allData != null && allData.size()>0){
tvShopcartEdit.setVisibility(View.VISIBLE);
llCheckAll.setVisibility(View.VISIBLE);
//有数据
//把当没有数据显示的布局隐藏
llViewNo.setVisibility(View.GONE);
//设置适配器
shoppingCartAdapter = new ShoppingCartAdapter(MainActivity.this,allData,tvShopcartTotal,checkboxAll,cbAll);
recyclerview.setLayoutManager(new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,false));
recyclerview.setAdapter(shoppingCartAdapter);
}else{
//没有数据 显示数据为空的页面
emprtyShppingCart();
}
}
private void emprtyShppingCart() {
llViewNo.setVisibility(View.VISIBLE);
tvShopcartEdit.setVisibility(View.GONE);
llDelete.setVisibility(View.GONE);
}
private void inistener() {
//设置默认状态的编辑
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() {
//设置状态文本为完成装填
tvShopcartEdit.setTag(ACTION_EDIT);
tvShopcartEdit.setText("编辑");
//变成非勾选
if(shoppingCartAdapter != null){
shoppingCartAdapter.checkAll_none(true);
shoppingCartAdapter.checkAll();
shoppingCartAdapter.ShowTotalPrice();
}
//删除的视图
llDelete.setVisibility(View.GONE);
//结算视图隐藏
llCheckAll.setVisibility(View.VISIBLE);
}
/**
* 完成状态
* */
private void showDelete() {
//设置状态文本为完成装填
tvShopcartEdit.setTag(ACTION_COMPLETE);
tvShopcartEdit.setText("完成");
//删除的视图
llDelete.setVisibility(View.VISIBLE);
//结算视图隐藏
llCheckAll.setVisibility(View.GONE);
}
@Override
public void onClick(View v) {
if (v == btnDelete) {
//删除选中
shoppingCartAdapter.deleteData();
//校验
shoppingCartAdapter.checkAll();
//数据大小为0
if(shoppingCartAdapter.getItemCount() == 0){
emprtyShppingCart();
}
}
}
}
4)适配器的编写
public class ShoppingCartAdapter extends RecyclerView.Adapter<ShoppingCartAdapter.ViewHolder> {
private Context context;
private List<GoodsBean> mAllData;
private TextView mTvShopcartTotal;
private CheckBox mCheckboxAll;
/**
* 完成状态下的删除
*/
private CheckBox mCbAll;
public ShoppingCartAdapter(Context mContext, List<GoodsBean> allData, TextView tvShopcartTotal, CheckBox checkboxAll, CheckBox cbAll) {
this.context = mContext;
this.mAllData = allData;
this.mTvShopcartTotal = tvShopcartTotal;
this.mCheckboxAll = checkboxAll;
this.mCbAll = cbAll;
/**
* 总金额
* */
ShowTotalPrice();
/**
* 设置点击事件
* */
setListener();
/**
* 校验是否全选
* */
checkAll();
}
/**
* 设置点击事件
*/
private void setListener() {
setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(int positon) {
//根据位置得到对应的bean
GoodsBean goodsBean = mAllData.get(positon);
//设置取反装填
goodsBean.setSelected(!goodsBean.isSelected());
//刷新数据
notifyItemChanged(positon);
//校验是否是全选
checkAll();
//重新计算
ShowTotalPrice();
}
});
//设置全选和非全选按钮的点击事件
mCheckboxAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//得到状态
boolean isChecked = mCheckboxAll.isChecked();
//根据状态设置全选和非全选
checkAll_none(isChecked);
//计算总价格
ShowTotalPrice();
}
});
mCbAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//得到状态
boolean isChecked = mCbAll.isChecked();
//根据状态设置全选非全选
checkAll_none(isChecked);
}
});
}
/**
* 设置全选和非全选
*/
public void checkAll_none(boolean isChecked) {
if (mAllData != null && mAllData.size() >= 0) {
for (int i = 0; i < mAllData.size(); i++) {
GoodsBean goodsBean = mAllData.get(i);
goodsBean.setSelected(isChecked);
notifyItemChanged(i);
}
}
}
/**
* 校验是否全选
*/
public void checkAll() {
if (mAllData != null && mAllData.size() >= 0) {
int number = 0;
for (int i = 0; i < mAllData.size(); i++) {
GoodsBean goodsBean = mAllData.get(i);
if (!goodsBean.isSelected()) {
//非全选
mCheckboxAll.setChecked(false);
mCbAll.setChecked(false);
} else {
number++;
}
}
if (number == mAllData.size()) {
//全选
mCheckboxAll.setChecked(true);
mCbAll.setChecked(true);
}
} else {
mCheckboxAll.setChecked(false);
mCbAll.setChecked(false);
}
}
/**
* 合计金额
*/
public void ShowTotalPrice() {
mTvShopcartTotal.setText("合计:" + getTotalPrices());
}
private double getTotalPrices() {
double totalPrice = 0.0;
if (mAllData != null && mAllData.size() >= 0) {
for (int i = 0; i < mAllData.size(); i++) {
GoodsBean goodsBean = mAllData.get(i);
if (goodsBean.isSelected()) {
totalPrice = totalPrice + Double.valueOf(goodsBean.getNumber()) * Double.valueOf(goodsBean.getCover_price());
}
}
}
return totalPrice;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = View.inflate(context, R.layout.item_shop_cart, null);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
//根据位置得到对应的bean
final GoodsBean goodsBean = mAllData.get(position);
//设置数据
holder.cb_gov.setChecked(goodsBean.isSelected());
Glide.with(context).load(goodsBean.getFigure()).into(holder.iv_gov);
holder.tv_desc_gov.setText(goodsBean.getName());
holder.tv_price_gov.setText("¥" + goodsBean.getCover_price());
holder.add_sub_view.setValue(goodsBean.getNumber());
holder.add_sub_view.setMinValue(1);
holder.add_sub_view.setMaxValue(100);
/**
* 设置商品数量的变化
* */
holder.add_sub_view.setOnNumberChangerListener(new AddSubView.OnNumberChangerListener() {
@Override
public void onNumberChange(int value) {
//列表更新
goodsBean.setNumber(value);
//刷新适配器
notifyItemChanged(position);
//再次计算总价格
ShowTotalPrice();
}
});
}
public void deleteData() {
if (mAllData != null && mAllData.size() > 0) {
for (int i = 0; i < mAllData.size(); i++) {
//删除选中的
GoodsBean goodsBean = mAllData.get(i);
if (goodsBean.isSelected()) {
//列表移除
mAllData.remove(goodsBean);
//刷新
notifyItemChanged(i);
}
}
}
}
@Override
public int getItemCount() {
return mAllData == null ? 0 : mAllData.size();
}
/**
* 监听者
*/
public interface OnItemClickListener {
/**
* 点击某一条目的时候暴露的接口方法
*/
void onItemClick(int positon);
}
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public 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 add_sub_view;
public ViewHolder(View itemView) {
super(itemView);
cb_gov = itemView.findViewById(R.id.cb_gov);
iv_gov = itemView.findViewById(R.id.iv_gov);
tv_desc_gov = itemView.findViewById(R.id.tv_desc_gov);
tv_price_gov = itemView.findViewById(R.id.tv_price_gov);
add_sub_view = itemView.findViewById(R.id.add_sub_view);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(getLayoutPosition());
}
}
});
}
}
}
5)适配器的item布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<CheckBox
android:id="@+id/cb_gov"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:button="@drawable/checkbox_selector"
android:checked="true"
android:clickable="false" />
<ImageView
android:id="@+id/iv_gov"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/ic_launcher"
android:scaleType="fitXY" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_desc_gov"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="2"
android:text="华硕(ASUS)经典系列X554LP 15.6英寸笔记本 (i5-5200U 4G 500G R5-M230 1G独显 蓝牙 Win8.1 黑色)"
android:textColor="#404040"
android:textSize="16sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_price_gov"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="¥0.0"
android:textColor="#f00"
android:textSize="16sp" />
<com.zzsy.shoppingcardemo.view.AddSubView
android:id="@+id/add_sub_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.6dp"
android:background="#22000000" />
</LinearLayout>
整个购物车功能就实现了,里面的注释讲解了该方法的作用。
项目地址:
csdn:
https://download.csdn.net/download/wk_beicai/11064669
github:
https://gitee.com/wangkuo_123456/shopping_cart.git