Fork me on github

Android之淘宝商品列表长按遮罩效果

先来看看淘宝、唯品会长按商品的效果,以及简单Demo的效果:

         

 

首先分析一下场景:

  1. 长按条目时,弹出遮罩的效果遮挡在原来的条目布局上;
  2. 页面滑动或点击其他的条目,上一个正在遮罩的条目遮罩消失。
  3. 长按其他条目时,上一个遮罩的条目撤销遮罩,当前长按的显示遮罩;
  4. 条目添加遮罩的时添加动画;

1. 遮罩的效果,我们会很容易的想到Android布局控件FrameLayout布局,是基于叠加在上方的布局。所以在列表条目布局的时候,可以使用FrameLayout布局,在长按列表条目时,用条目的根布局添加一个遮罩的布局,就达到我们想要的效果了。

 

 

2. 记录当前长按的根布局,如果点击或长按其他的列表条目,亦或滑动页面(添加活动监听)时,就取消之前长按的条目遮罩,从条目根布局中删除遮罩布局就OK了;

3. 可以利用View动画或属性动画,在添加遮罩布局时显示动画;

 

 

 接下来, 来撸一下代码吧:

 1. 首先,先定义一下遮罩的布局,根据需求自定义View

/***
 * 长按条目遮罩界面
 */
public class ItemMaskLayout extends LinearLayout {

    public ItemMaskLayout(Context context) {
        this(context, null);
    }

    public ItemMaskLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ItemMaskLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        LayoutInflater.from(context).inflate(R.layout.layout_product_list_item_mask, this, true);

        findViewById(R.id.tv_find_same).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mItemMaskClickListener != null) {
                    mItemMaskClickListener.findTheSame();
                }
            }
        });

        findViewById(R.id.tv_collection).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mItemMaskClickListener != null) {
                    mItemMaskClickListener.collection();
                }
            }
        });
    }

    public ItemMaskClickListener mItemMaskClickListener;

    public void setMaskItemClickListener(ItemMaskClickListener listener) {
        this.mItemMaskClickListener = listener;
    }

    //提供遮罩中按钮点击操作接口  自定义
    public interface ItemMaskClickListener {
        void findTheSame();
        void collection();
    }
}

 

2. 封装一个帮助类,主要是根据该类的成员变量根据长按的条目指向列表Item的布局,然后为条目添加遮罩的效果;

/**
 * 长按条目添加遮罩操作帮助类
 */
public class ItemLongClickMaskHelper {

    private FrameLayout mRootFrameLayout;
    private ItemMaskLayout mMaskItemLayout;
    private Context mContext;
    private ScaleAnimation anim;
    private String productId;

    public ItemLongClickMaskHelper(Context context){
        this.mContext = context;
        mMaskItemLayout = new ItemMaskLayout(mContext);
        anim = new ScaleAnimation(
                0f, 1.0f, 1.0f, 1.0f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f
        );
        anim.setDuration(300);
        mMaskItemLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismissItemMaskLayout();
            }
        });

        mMaskItemLayout.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                dismissItemMaskLayout();
                return true;
            }
        });

        mMaskItemLayout.setMaskItemClickListener(new ItemMaskLayout.ItemMaskClickListener() {
            @Override
            public void findTheSame() {
                ToastUtil.showCustomToast("找相似 " + productId);
            }

            @Override
            public void collection() {
                ToastUtil.showCustomToast("收藏 " + productId);
            }
        });
    }

    public ItemLongClickMaskHelper setRootFrameLayout(FrameLayout frameLayout, String fundId){
        if (mRootFrameLayout != null){
            mRootFrameLayout.removeView(mMaskItemLayout);
        }
        mRootFrameLayout = frameLayout;
        this.productId = fundId;
        mRootFrameLayout.addView(mMaskItemLayout);
        mMaskItemLayout.startAnimation(anim);
        return this;
    }

    public ItemLongClickMaskHelper setMaskItemListener(ItemMaskLayout.ItemMaskClickListener listener){
        this.mMaskItemLayout.setMaskItemClickListener(listener);
        return this;
    }

    /**
     * 遮罩消失
     */
    public void dismissItemMaskLayout(){
        if (mRootFrameLayout != null){
            mRootFrameLayout.removeView(mMaskItemLayout);
        }
    }
}

 

3.注意在滑动RecyclerView列表的时候,监听滑动,撤销遮罩,直接定义RecyclerView的子类,添加滑动监听回调;

 

public class TouchCallbackRecyclerView extends RecyclerView {
    
    public TouchCallbackRecyclerView(Context context) {
        super(context);
    }

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

    public TouchCallbackRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public interface ScrollCallback {
        /**
         * 滑动手指抬起事件
         *
         * @param diffY 抬起时相对于按下时的偏移量<br/>大于0:列表往下拉, 小于0: 列表往上拉
         */
        void onTouchUp(float diffY);
    }

    private ScrollCallback mScrollCallback;

    public void setScrollCallback(ScrollCallback callback) {
        this.mScrollCallback = callback;
    }

    private float mDownY, mMovingY, mUpY;
    private boolean isUp = false;

    @SuppressWarnings("deprecation")
    private static final float SLOP = ViewConfiguration.getTouchSlop();

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownY = ev.getY();
                isUp = false;

                break;
            case MotionEvent.ACTION_MOVE:
                mMovingY = ev.getY();
                isUp = false;
                break;
            case MotionEvent.ACTION_UP:
                mUpY = ev.getY();
                isUp = true;
                break;
        }
        if (isUp && mScrollCallback != null && Math.abs(mUpY - mDownY) > SLOP) {
            mScrollCallback.onTouchUp(mMovingY - mDownY);
        }
        return super.dispatchTouchEvent(ev);
    }
}

以上就是主要的代码实现部分,灵活地扩展应用ItemLongClickMaskHelper基本就能实现类似淘宝长按遮罩效果了。

源码地址:https://github.com/denluoyia/ItemLongClickMaskDemo

 

posted @ 2018-05-09 19:13  Denluoyia  阅读(1562)  评论(0编辑  收藏  举报
返回顶部