前言
电商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();
}
}
效果如下(没想到这么小的一个组件吧...):
主要的点以上代码都包含了,这样需要购物车的位置直接添加上这个组件基本上就不需要额外处理了,代码中简单写了说明,如有错误,还请指正~
网友评论