Android购物车组件

前言

电商App中存在大量的购物车小按钮,可以直接加入购物车,有时还会配合动画效果,封装一下复用是一种不错的选择

实现

需要考虑以下几点:

1.修改UI:

不同位置的购物车图标大小不同,显示数量的红点相对位置也可能不同,项目中最常用的大小设置为默认的,提供修改UI的方法(因为可能购物车还需要在一个xml中被多种adapter复用)

2.向服务器提交加购:

添加购物车请求接口放在外部还是内部,如果放在外部每个地方都需要单独写一次请求服务器的方法,放在内部则不需要每次都处理加购物车的操作,此时我们需要购物车绑定添加商品时需要的参数--商品id

3.添加动画:

加购物车成功时有的时候需要动画,给组件添加一个接口回调,在需要有加购物车之外的动画时给外部处理,因为动画效果一般与购物车无关,且在不同位置可能会不同,交给外部更自由也更方便。

4.同步购物车数量:

购物车在adapter中使用时滑出屏幕会回收,进入屏幕会重建,在某个位置对商品添加购物车之后,返回到之前的商品列表页面(此时该商品可能在屏幕中,也可能滑出去了),考虑在添加到屏幕上时设置监听,并更新此商品购物车数量,滑出屏幕时移除监听。屏幕上的商品靠监听来更新购物车数量,屏幕外的商品靠进入屏幕时获取缓存的购物车数据更新购物车数量,为了方便,将更新购物车数量封装到一个方法中并控制红点是否显示。

代码实现:

public class HomeCartView extends LinearLayout {


    private Context mContext;
    private int goods_id;//商品id

    private RelativeLayout rl_container;
    private ImageView iv_cart;
    private TextView tv_cart_num;

    private int cart_width;
    private int cart_height;
    private int container_height;
    private int cart_num_height;
    private int cart_num_size;
    private int cart_num_start;
    private int cart_num_bottom;

    private AddFinishListener listener;

    public HomeCartView(Context context) {
        super(context);
        initView(context,null);
    }

    public HomeCartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView(context,attrs);
    }

    private void initView(Context context,AttributeSet attrs) {
        mContext = context;
        initAttar(context,attrs);
        initUi();
    }

    public void setListener(AddFinishListener listener){
        this.listener = listener;
    }

    private void initUi() {
        View view = LayoutInflater.from(mContext).inflate(R.layout.home_cart_view,this,true);
        rl_container = view.findViewById(R.id.rl_container);
        iv_cart = view.findViewById(R.id.iv_cart);
        tv_cart_num = view.findViewById(R.id.tv_cart_num);
        setUi();
        view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                buy();
            }
        });
    }

    //将获取到的属性或者默认值设置给ui
    private void setUi(){
        rl_container.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,container_height));
        RelativeLayout.LayoutParams rlps = new RelativeLayout.LayoutParams(cart_width,cart_height);
        rlps.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        iv_cart.setLayoutParams(rlps);
        RelativeLayout.LayoutParams lps = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,cart_num_height);
        lps.bottomMargin = cart_num_bottom;
        lps.leftMargin = cart_num_start;
        lps.addRule(RelativeLayout.RIGHT_OF,R.id.iv_cart);
        tv_cart_num.setLayoutParams(lps);
        tv_cart_num.setTextSize(TypedValue.COMPLEX_UNIT_PX,cart_num_size);
    }

  //提供动态修改UI的方法
    public void modifyView(int container_height,int cart_w,int cart_h, int cart_num_height,int cart_num_bottom,int cart_num_start,int cart_num_size){
        this.container_height = DisplayUtil.dip2px(mContext,container_height);
        this.cart_width = DisplayUtil.dip2px(mContext,cart_w);
        this.cart_height = DisplayUtil.dip2px(mContext,cart_h);
        this.cart_num_height = DisplayUtil.dip2px(mContext,cart_num_height);
        this.cart_num_bottom = DisplayUtil.dip2px(mContext,cart_num_bottom);
        this.cart_num_start = DisplayUtil.dip2px(mContext,cart_num_start);
        this.cart_num_size = DisplayUtil.sp2px(mContext,cart_num_size);
        setUi();
    }

    public void setCartImageResource(int mipmap){
        if(iv_cart == null) return;
        iv_cart.setImageResource(mipmap);
    }
    //取默认或者xml中定义的属性值
    private void initAttar(Context context, AttributeSet attrs) {
        if(attrs!=null){
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HomeCartView);
            cart_width = typedArray.getDimensionPixelSize(R.styleable.HomeCartView_cart_width, DisplayUtil.dip2px(context,25));
            cart_height = typedArray.getDimensionPixelSize(R.styleable.HomeCartView_cart_height,DisplayUtil.dip2px(context,25));
            cart_num_height = typedArray.getDimensionPixelSize(R.styleable.HomeCartView_cart_num_height,DisplayUtil.dip2px(context,12));
            container_height = typedArray.getDimensionPixelSize(R.styleable.HomeCartView_container_height, DisplayUtil.dip2px(context,29));
            cart_num_start = typedArray.getDimensionPixelSize(R.styleable.HomeCartView_cart_num_start, DisplayUtil.dip2px(context,-16));
            cart_num_bottom = typedArray.getDimensionPixelSize(R.styleable.HomeCartView_cart_num_bottom, DisplayUtil.dip2px(context,-8));
            cart_num_size = typedArray.getDimensionPixelSize(R.styleable.HomeCartView_cart_num_size,DisplayUtil.sp2px(context,8));
            typedArray.recycle();
        }
    }

    //与服务器交互,加入购物车,并根据需要处理回调(需要服务器返回总购物车内的商品更新缓存)
    private void buy() {
       调用服务器接口,并在成功后判断是否需要外部进一步处理(添加动画等)
      if(listener!=null){//添加购物车之外的特别处理
           listener.onAddFinish();
      }
    }

  //绑定商品id
    public void setData(int goods_id){
        this.goods_id = goods_id;
    }

  //处理不同情况下的购物车数量展示 为登录设置number为0
    public void setCartNum(int number){
        if(tv_cart_num == null) return;
        if(TextUtils.isEmpty(CartUtil.getSessionId(mContext))){
            number = 0;
        }
        if(number <= 0){
            tv_cart_num.setVisibility(GONE);
        }else{
            tv_cart_num.setVisibility(VISIBLE);
            tv_cart_num.setText(String.valueOf(number));
        }
    }

    //从屏幕移除时取消监听
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        EventBus.getDefault().unregister(this);
    }

    //添加到屏幕上时设置监听,并且更新当前购物车数量
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        EventBus.getDefault().register(this);
        updateCurNumber();
    }

    private void updateCurNumber(){
        if(tv_cart_num!=null){
            String cacheStr = CartUtil.getCartGoodsNumber(mContext);//从缓存中获取购物车商品数据
            if(!TextUtils.isEmpty(cacheStr)){
                try {
                    JSONObject obj = new JSONObject(cacheStr);
                    if(obj.has(goods_id+"")){
                        setCartNum(obj.optInt(goods_id+""));
                    }else{
                        setCartNum(0);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }else{
                setCartNum(0);
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onHandleCartEvent(HandleCartEvent event){
        updateCurNumber();
    }

    public interface AddFinishListener{
        void onAddFinish();
    }

}

效果如下(没想到这么小的一个组件吧...):


主要的点以上代码都包含了,这样需要购物车的位置直接添加上这个组件基本上就不需要额外处理了,代码中简单写了说明,如有错误,还请指正~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容