先看效果图。。。
项目中用到每次都是复制以前的项目中的 ,在此做个记录下次方便查看
购物车用到BottomSheetLayout 底部弹出框和开源库StickyListHeadersListView来实现ListView列表分组效果( https://blog.csdn.net/zuiwuyuan/article/details/49872533)
public class ShoppingCartActivity extends AppCompatActivity implements View.OnClickListener {
private ImageView imgCart;
private RecyclerView rvType, rvSelected;
private TextView tvCount, tvCost, tvSubmit, tvTips;
private BottomSheetLayout bottomSheetLayout;
private View bottomSheet;
private StickyListHeadersListView listView;
private ArrayList dataList, typeList;
private SparseArray selectedList;//购物车数据
private SparseIntArray groupSelect;//购物车数据数量
private GoodsAdapter myAdapter;//右 数据适配器
private SelectAdapter selectAdapter;//购物车弹出框 适配器
private TypeAdapter typeAdapter;//种类适配器
private NumberFormat nf;
private Handler mHanlder;
private ViewGroup anim_mask_layout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shopping_cart);
nf = NumberFormat.getCurrencyInstance();
nf.setMaximumFractionDigits(2);
mHanlder = new Handler(getMainLooper());
dataList = GoodsItem.getGoodsList();//右数据
typeList = GoodsItem.getTypeList();//左类数据
selectedList = new SparseArray<>();//购物车数据
groupSelect = new SparseIntArray();//左数量
initView();
}
private void initView() {
tvCount = (TextView) findViewById(R.id.tvCount);
tvCost = (TextView) findViewById(R.id.tvCost);
tvTips = (TextView) findViewById(R.id.tvTips);
tvSubmit = (TextView) findViewById(R.id.tvSubmit);
rvType = (RecyclerView) findViewById(R.id.typeRecyclerView);
imgCart = (ImageView) findViewById(R.id.imgCart);
anim_mask_layout = (RelativeLayout) findViewById(R.id.containerLayout);
bottomSheetLayout = (BottomSheetLayout) findViewById(R.id.bottomSheetLayout);
listView = (StickyListHeadersListView) findViewById(R.id.itemListView);
rvType.setLayoutManager(new LinearLayoutManager(this));
typeAdapter = new TypeAdapter(this, typeList);
rvType.setAdapter(typeAdapter);
rvType.addItemDecoration(new DividerDecoration(this));
myAdapter = new GoodsAdapter(dataList, this);
listView.setAdapter((StickyListHeadersAdapter) myAdapter);
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) {
GoodsItem item = dataList.get(firstVisibleItem);
if (typeAdapter.selectTypeId != item.typeId) {
typeAdapter.selectTypeId = item.typeId;
typeAdapter.notifyDataSetChanged();
rvType.smoothScrollToPosition(getSelectedGroupPosition(item.typeId));
}
}
});
}
public void playAnimation(int[] start_location) {
ImageView img = new ImageView(this);
img.setImageResource(R.drawable.circle_red);
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;
}
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);
}
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) {
mHanlder.postDelayed(new Runnable() {
@Override
public void run() {
anim_mask_layout.removeView(v);
}
}, 100);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
v.startAnimation(set);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bottom:
showBottomSheet();
break;
case R.id.clear:
clearCart();
break;
case R.id.tvSubmit:
Toast.makeText(ShoppingCartActivity.this, "结算", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
//添加商品
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);
}
//移除商品
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);
}
//刷新布局 总价、购买数量等
private void update(boolean refreshGoodList) {
int size = selectedList.size();
int count = 0;
double cost = 0;
for (int i = 0; i < size; i++) {
GoodsItem item = selectedList.valueAt(i);
count += item.count;
cost += item.count * item.price;
}
if (count < 1) {
tvCount.setVisibility(View.GONE);
} else {
tvCount.setVisibility(View.VISIBLE);
}
tvCount.setText(String.valueOf(count));
if (cost > 99.99) {
tvTips.setVisibility(View.GONE);
tvSubmit.setVisibility(View.VISIBLE);
} else {
tvSubmit.setVisibility(View.GONE);
tvTips.setVisibility(View.VISIBLE);
}
tvCost.setText(nf.format(cost));
if (myAdapter != null && refreshGoodList) {
myAdapter.notifyDataSetChanged();
}
if (selectAdapter != null) {
selectAdapter.notifyDataSetChanged();
}
if (typeAdapter != null) {
typeAdapter.notifyDataSetChanged();
}
if (bottomSheetLayout.isSheetShowing() && selectedList.size() < 1) {
bottomSheetLayout.dismissSheet();
}
}
//清空购物车
public void clearCart() {
selectedList.clear();
groupSelect.clear();
update(true);
}
//根据商品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);
}
//根据类别id获取分类的Position 用于滚动左侧的类别列表
public int getSelectedGroupPosition(int typeId) {
for (int i = 0; i < typeList.size(); i++) {
if (typeId == typeList.get(i).typeId) {
return i;
}
}
return 0;
}
public void onTypeClicked(int typeId) {
listView.setSelection(getSelectedPosition(typeId));
}
private int getSelectedPosition(int typeId) {
int position = 0;
for (int i = 0; i < dataList.size(); i++) {
if (dataList.get(i).typeId == typeId) {
position = i;
break;
}
}
return position;
}
private View createBottomSheetView() {
Log.e("sss","444");
View view = LayoutInflater.from(this).inflate(R.layout.layout_bottom_sheet, (ViewGroup) getWindow().getDecorView(), false);
rvSelected = (RecyclerView) view.findViewById(R.id.selectRecyclerView);
rvSelected.setLayoutManager(new LinearLayoutManager(this));
TextView clear = (TextView) view.findViewById(R.id.clear);
clear.setOnClickListener(this);
selectAdapter = new SelectAdapter(this, selectedList);
rvSelected.setAdapter(selectAdapter);
return view;
}
private void showBottomSheet() {
if (bottomSheet == null) {
bottomSheet = createBottomSheetView();
Log.e("sss","111");
}
if (bottomSheetLayout.isSheetShowing()) {
bottomSheetLayout.dismissSheet();
Log.e("sss","222");
} else {
if (selectedList.size() != 0) {
bottomSheetLayout.showWithSheetView(bottomSheet);
Log.e("sss","333");
}
}
}
}
左边列表adapter(左右关联)
public class TypeAdapter extends RecyclerView.Adapter {
public int selectTypeId;
public ShoppingCartActivity activity;
public ArrayList dataList;
public TypeAdapter(ShoppingCartActivity activity, ArrayList dataList) {
this.activity = activity;
this.dataList = dataList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type,parent,false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
GoodsItem item = dataList.get(position);
holder.bindData(item);
}
@Override
public int getItemCount() {
if(dataList==null){
return 0;
}
return dataList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView tvCount,type;
private GoodsItem item;
public ViewHolder(View itemView) {
super(itemView);
tvCount = (TextView) itemView.findViewById(R.id.tvCount);
type = (TextView) itemView.findViewById(R.id.type);
itemView.setOnClickListener(this);
}
@SuppressLint("ResourceAsColor")
public void
bindData(GoodsItem item){
this.item = item;
type.setText(item.typeName);
Log.e("pppp","adapter "+activity.getSelectedGroupCountByTypeId(item.typeId)+"");
int count = activity.getSelectedGroupCountByTypeId(item.typeId);
tvCount.setText(String.valueOf(count));
if(count<1){
tvCount.setVisibility(View.GONE);
}else{
tvCount.setVisibility(View.VISIBLE);
}
if(item.typeId==selectTypeId){
itemView.setBackgroundColor(Color.RED);
}else{
itemView.setBackgroundColor(Color.WHITE);
}
}
@Override
public void onClick(View v) {
activity.onTypeClicked(item.typeId);
}
}
}
右边列表adapter
public class GoodsAdapter extends BaseAdapter implements StickyListHeadersAdapter {
private ArrayList dataList;
private ShoppingCartActivity mContext;
private NumberFormat nf;
private LayoutInflater mInflater;
public GoodsAdapter(ArrayList dataList, ShoppingCartActivity mContext) {
this.dataList = dataList;
this.mContext = mContext;
nf = NumberFormat.getCurrencyInstance();
nf.setMaximumFractionDigits(2);
mInflater = LayoutInflater.from(mContext);
}
@Override
public View getHeaderView(int position, View convertView, ViewGroup parent) {
if(convertView==null) {
convertView = mInflater.inflate(R.layout.item_header_view, parent, false);
}
((TextView)(convertView)).setText(dataList.get(position).typeName);
return convertView;
}
@Override
public long getHeaderId(int position) {
return dataList.get(position).typeId;
}
@Override
public int getCount() {
if(dataList==null){
return 0;
}
return dataList.size();
}
@Override
public Object getItem(int position) {
return dataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ItemViewHolder holder = null;
if(convertView==null){
convertView = mInflater.inflate(R.layout.item_goods,parent,false);
holder = new ItemViewHolder(convertView);
convertView.setTag(holder);
}else{
holder = (ItemViewHolder) convertView.getTag();
}
GoodsItem item = dataList.get(position);
holder.bindData(item);
return convertView;
}
class ItemViewHolder implements View.OnClickListener{
private TextView name,price,tvAdd,tvMinus,tvCount;
private GoodsItem item;
private RatingBar ratingBar;
public ItemViewHolder(View itemView) {
name = (TextView) itemView.findViewById(R.id.tvName);
price = (TextView) itemView.findViewById(R.id.tvPrice);
tvCount = (TextView) itemView.findViewById(R.id.count);
tvMinus = (TextView) itemView.findViewById(R.id.tvMinus);
tvAdd = (TextView) itemView.findViewById(R.id.tvAdd);
ratingBar = (RatingBar) itemView.findViewById(R.id.ratingBar);
tvMinus.setOnClickListener(this);
tvAdd.setOnClickListener(this);
}
public void bindData(GoodsItem item){
Log.e("TAG", "bindData: " );
this.item = item;
name.setText(item.name);
ratingBar.setRating(item.rating);
item.count = mContext.getSelectedItemCountById(item.id);//根据商品id获取当前商品的采购数量
tvCount.setText(String.valueOf(item.count));
price.setText(nf.format(item.price));
if(item.count<1){
tvCount.setVisibility(View.GONE);
tvMinus.setVisibility(View.GONE);
}else{
tvCount.setVisibility(View.VISIBLE);
tvMinus.setVisibility(View.VISIBLE);
}
}
@Override
public void onClick(View v) {
ShoppingCartActivity activity = mContext;
switch (v.getId()){
case R.id.tvAdd: {
int count = activity.getSelectedItemCountById(item.id);
if (count < 1) {
tvMinus.setAnimation(getShowAnimation());
tvMinus.setVisibility(View.VISIBLE);
tvCount.setVisibility(View.VISIBLE);
}
activity.add(item, false);
count++;
tvCount.setText(String.valueOf(count));
int[] loc = new int[2];
v.getLocationInWindow(loc);
activity.playAnimation(loc);
}
break;
case R.id.tvMinus: {
int count = activity.getSelectedItemCountById(item.id);
if (count < 2) {
tvMinus.setAnimation(getHiddenAnimation());
tvMinus.setVisibility(View.GONE);
tvCount.setVisibility(View.GONE);
}
count--;
activity.remove(item, false);//activity.getSelectedItemCountById(item.id)
tvCount.setText(String.valueOf(count));
}
break;
default:
break;
}
}
}
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;
}
}
购物车adapter
public class SelectAdapter extends RecyclerView.Adapter{
private ShoppingCartActivity activity;
private SparseArray dataList;
private NumberFormat nf;
private LayoutInflater mInflater;
public SelectAdapter(ShoppingCartActivity activity, SparseArray dataList) {
this.activity = activity;
this.dataList = dataList;
nf = NumberFormat.getCurrencyInstance();
nf.setMaximumFractionDigits(2);
mInflater = LayoutInflater.from(activity);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_selected_goods,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
GoodsItem item = dataList.valueAt(position);
holder.bindData(item);
}
@Override
public int getItemCount() {
if(dataList==null) {
return 0;
}
return dataList.size();
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private GoodsItem item;
private TextView tvCost,tvCount,tvAdd,tvMinus,tvName;
public ViewHolder(View itemView) {
super(itemView);
tvName = (TextView) itemView.findViewById(R.id.tvName);
tvCost = (TextView) itemView.findViewById(R.id.tvCost);
tvCount = (TextView) itemView.findViewById(R.id.count);
tvMinus = (TextView) itemView.findViewById(R.id.tvMinus);
tvAdd = (TextView) itemView.findViewById(R.id.tvAdd);
tvMinus.setOnClickListener(this);
tvAdd.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tvAdd:
activity.add(item, true);
break;
case R.id.tvMinus:
activity.remove(item, true);
break;
default:
break;
}
}
public void bindData(GoodsItem item){
this.item = item;
tvName.setText(item.name);
tvCost.setText(nf.format(item.count*item.price));
tvCount.setText(String.valueOf(item.count));
}
}
}
数据源 (自己随便加的 )
public class GoodsItem {
public int id;
public int typeId;
public int rating;
public String name;
public String typeName;
public double price;
public int count;//
public GoodsItem(int id, double price, String name, int typeId, String typeName) {
this.id = id;
this.price = price;
this.name = name;
this.typeId = typeId;
this.typeName = typeName;
rating = new Random().nextInt(5) + 1;
}
private static ArrayList goodsList;
private static ArrayList typeList;
private static void initData() {
goodsList = new ArrayList<>();
typeList = new ArrayList<>();
GoodsItem item = null;
for(int i=1;i<4;i++){ //外层
for(int j=1;j<15;j++){ //里面层
Log.e("sss",100*i+j+"");
item = new GoodsItem(100*i+j,Math.random()*100,"商品"+(100*i+j),i,"种类种类"+i);
goodsList.add(item);
}
typeList.add(item);
}
}
public static ArrayList getGoodsList() {
if (goodsList == null) {
initData();
}
return goodsList;
}
public static ArrayList getTypeList() {
if (typeList == null) {
initData();
}
return typeList;
}
}
最后DividerDecoration类 分割线 可以在自己百度。。。
布局文件(activity_shopping_cart)
布局文件(item_goods.xml)
布局文件(item_header_view.xml)
布局文件(item_selected_goods.xml)
布局文件(item_type.xml)
布局文件(layout_bottom_sheet.xml)
布局文件(layout_mian_shopping_cart.xml)
最后附上下载地址:https://gitee.com/oubajunping/shopping-cart.git