Android 左滑刪除控件

背景:在android開發(fā)中,列表是經(jīng)常會(huì)使用到的一個(gè)主要控件,列表中可以展示大量的數(shù)據(jù),像訂單、商品、通訊錄、瀏覽記錄或者關(guān)注列表等等。可能產(chǎn)品一開始需求只做簡(jiǎn)單的數(shù)據(jù)展示,但后期隨著功能越來越多,越來越完善,產(chǎn)品可能說在列表里面增加一些交互能力。比如說訂單列表里面,一開始只是展示訂單數(shù)據(jù),后面需要加上刪除訂單的功能,以前Android中這種功能要的很多的可能就是長(zhǎng)按操作這種的,因?yàn)槌绦蛟持恍枰苌俚拇a就能實(shí)現(xiàn)。但是ios的習(xí)慣操作是左滑刪除,為了保持統(tǒng)一的操作習(xí)慣,兩端保持一致,最終產(chǎn)品會(huì)讓Android程序猿去實(shí)現(xiàn)一種和ios一模一樣的功能。如果你的代碼已經(jīng)維護(hù)了很久,代碼量比較大,不愿意去大改,那么今天這個(gè)控件就能輕松的助你完成左滑刪除的功能。

先上效果圖:

效果圖.gif

設(shè)計(jì)思路:最好以最小的代碼侵入來實(shí)現(xiàn)左滑刪除的功能,在不破壞原來邏輯的基礎(chǔ)上,只需稍加改造便可具備左滑刪除的能力。
首先分析下左滑刪除的基礎(chǔ)原理:

左滑刪除.png

原理分析:

  1. 正常狀態(tài)下,我們看到的是完整的內(nèi)容部分,右側(cè)菜單部分因?yàn)槌銎聊凰圆辉谝暰€范圍內(nèi)。
  2. 手指滑動(dòng)過程中,容器的內(nèi)容跟隨手指移動(dòng),從而拉出在屏幕外面的菜單區(qū)域。
  3. 當(dāng)手指松開的時(shí)候,我們先假定一種邏輯,如果菜單區(qū)域顯示超過一半,那就全部顯示;如果少于一半那就滑出隱藏。

滑動(dòng)原理分析完了之后,我們大概就有了實(shí)現(xiàn)思路了:

  1. 首先我們的控件里面需要兩塊區(qū)域,因?yàn)橐郧翱赡芤呀?jīng)實(shí)現(xiàn)了列表item的顯示,如果能不做任何改動(dòng),直接把以前的item包含到我們的內(nèi)容區(qū)域里面來,那么我們內(nèi)容區(qū)域就輕松搞定了。
  2. 菜單區(qū)域,需要什么能力,就把相關(guān)的View也傳遞給我容器,然后容器放到相應(yīng)位置。

談笑間,簡(jiǎn)單兩步我們的左滑刪除容器已經(jīng)完成一個(gè)簡(jiǎn)單的雛形了!

接下來就是代碼實(shí)現(xiàn):

步驟一:內(nèi)容和菜單分別加入容器

/**
     * 設(shè)置內(nèi)容區(qū)域
     * @param contentView
     */
    public void addContentView(View contentView) {
        this.mContentView = contentView;
        this.mContentView.setTag("contentView");
        
        View cv = findViewWithTag("contentView");
        if (cv != null) {
            this.removeView(cv);
        }
        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
        );
        this.addView(this.mContentView, layoutParams);
    }
    
    /**
     * 設(shè)置右邊菜單區(qū)域
     */
    public void addMenuView(View menuView) {
        this.mMenuView = menuView;
        this.mMenuView.setTag("menuView");
        
        View mv = findViewWithTag("menuView");
        if (mv != null) {
            this.removeView(mv);
        }
        LayoutParams layoutParams = new LayoutParams(mRightCanSlide, ViewGroup.LayoutParams.MATCH_PARENT);
        this.addView(this.mMenuView, layoutParams);
    }

步驟二:左滑處理

/**
     * 攔截觸摸事件
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        
        int actionMasked = ev.getActionMasked();
        
        Log.e(TAG, "onInterceptTouchEvent: actionMasked = " + actionMasked);
        
        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                mInitX = ev.getRawX() + getScrollX();
                mInitY = ev.getRawY();
                clearAnim();
                
                if (mViewPager != null) {
                    mViewPager.requestDisallowInterceptTouchEvent(true);
                }
                
                if (mCardView != null) {
                    mCardView.requestDisallowInterceptTouchEvent(true);
                }
                
                break;
            
            case MotionEvent.ACTION_MOVE:
                
                if (mInitX - ev.getRawX() < 0) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                    
                    // 阻止ViewPager攔截事件
                    if (mViewPager != null) {
                        mViewPager.requestDisallowInterceptTouchEvent(true);
                    }
                    
                    return false;
                }
                
                // y軸方向上達(dá)到滑動(dòng)最小距離, x 軸未達(dá)到
                if (Math.abs(ev.getRawY() - mInitY) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) > Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                    
                    return false;
                    
                }
                
                // x軸方向達(dá)到了最小滑動(dòng)距離,y軸未達(dá)到
                if (Math.abs(mInitX - ev.getRawX() - getScrollX()) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) <= Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 阻止父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(true);
                        isReCompute = false;
                    }
                    
                    return true;
                }
                
                break;
            
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                
                if (mRecyclerView != null) {
                    mRecyclerView.requestDisallowInterceptTouchEvent(false);
                    isReCompute = true;
                }
                break;
            default:
                break;
        }
        
        return super.onInterceptTouchEvent(ev);
    }
/**
     * 處理觸摸事件
     * 需要注意何時(shí)處理左滑,何時(shí)不處理
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        
        int actionMasked = ev.getActionMasked();
        
        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                mInitX = ev.getRawX() + getScrollX();
                mInitY = ev.getRawY();
                clearAnim();
                
                if (mViewPager != null) {
                    mViewPager.requestDisallowInterceptTouchEvent(true);
                }
                
                if (mCardView != null) {
                    mCardView.requestDisallowInterceptTouchEvent(true);
                }
                
                break;
            
            case MotionEvent.ACTION_MOVE:
                
                if (mInitX - ev.getRawX() < 0) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                    
                    // 阻止ViewPager攔截事件
                    if (mViewPager != null) {
                        mViewPager.requestDisallowInterceptTouchEvent(true);
                        isReCompute = false;
                    }
                }
                
                // y軸方向上達(dá)到滑動(dòng)最小距離, x 軸未達(dá)到
                if (Math.abs(ev.getRawY() - mInitY) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) > Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                }
                
                // x軸方向達(dá)到了最小滑動(dòng)距離,y軸未達(dá)到
                if (Math.abs(mInitX - ev.getRawX() - getScrollX()) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) <= Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 阻止父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(true);
                        isReCompute = false;
                    }
                }
                
                
                /** 如果手指移動(dòng)距離超過最小距離 */
                float translationX = mInitX - ev.getRawX();
                
                // 如果滑動(dòng)距離已經(jīng)大于右邊可伸縮的距離后, 應(yīng)該重新設(shè)置initx
                if (translationX > mRightCanSlide) {
                    mInitX = ev.getRawX() + mRightCanSlide;
                    
                }
                
                // 如果互動(dòng)距離小于0,那么重新設(shè)置初始位置initx
                if (translationX < 0) {
                    mInitX = ev.getRawX();
                }
                
                translationX = translationX > mRightCanSlide ? mRightCanSlide : translationX;
                translationX = translationX < 0 ? 0 : translationX;
                
                // 向左滑動(dòng)
                if (translationX <= mRightCanSlide && translationX >= 0) {
                    
                    scrollTo((int) translationX, 0);
                    
                    return true;
                }
                
                break;
            
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                
                if (mRecyclerView != null) {
                    mRecyclerView.requestDisallowInterceptTouchEvent(false);
                    isReCompute = true;
                }
                
                upAnim();
                
                return true;
                
                default:
                    break;
        }
        
        return true;
    }

以上兩個(gè)方法主要處理了左滑移動(dòng)功能以及滑動(dòng)沖突問題,如果用的是RecyclerView那么為了防止垂直方向的同向沖突,那么需要將外層的RecyclerView傳入左滑容器,在這個(gè)容器中會(huì)處理滑動(dòng)沖突。

到這就已經(jīng)實(shí)現(xiàn)了左滑功能,并且解決掉了垂直方向上的滑動(dòng)沖突,然后我們還要實(shí)現(xiàn)一個(gè)功能是:如果有一個(gè)item向左滑動(dòng)并顯示出右邊的菜單區(qū)域,當(dāng)手指再次按下或者列表滑動(dòng)的時(shí)候,需要將已經(jīng)顯示菜單區(qū)域的item收起,恢復(fù)原來的狀態(tài)。為了提供這個(gè)能力,左滑容器里面提供一個(gè)菜單狀態(tài)變化的監(jiān)聽:

/**
     * 刪除按鈕狀態(tài)變化監(jiān)聽
     */
    public interface OnDelViewStatusChangeLister {
        
        /**
         * 狀態(tài)變化監(jiān)聽
         * @param show  是否正在顯示
         */
        void onStatusChange(boolean show);
    }


/**
     * 重置 菜單展開/菜單收起 狀態(tài)
     */
    public void resetDelStatus() {
        
        int scrollX = getScrollX();
        
        if (scrollX == 0) {
            return;
        }
        
        clearAnim();
        
        mValueAnimator = ValueAnimator.ofInt(scrollX, 0);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                
                scrollTo(value, 0);
            }
        });
        
        mValueAnimator.setDuration(mAnimDuring);
        mValueAnimator.start();
    }

菜單展開或者收起都會(huì)調(diào)用這個(gè)方法,方便第三方調(diào)用者處理狀態(tài)。

再者還有就是加上動(dòng)畫,讓滑動(dòng)更加柔和:

/**
     * 手指抬起執(zhí)行動(dòng)畫
     */
    private void upAnim() {
        int scrollX = getScrollX();
        
        if (scrollX == mRightCanSlide || scrollX == 0) {
            
            if (mStatusChangeLister != null) {
                mStatusChangeLister.onStatusChange(scrollX == mRightCanSlide);
            }
            
            return;
        }
        
        clearAnim();
        
        // 如果顯出一半松開手指,那么自動(dòng)完全顯示。否則完全隱藏
        if (scrollX >= mRightCanSlide / 2) {
            mValueAnimator = ValueAnimator.ofInt(scrollX, mRightCanSlide);
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int value = (int) animation.getAnimatedValue();
                    
                    scrollTo(value, 0);
                }
            });
            
            mValueAnimator.setDuration(mAnimDuring);
            mValueAnimator.start();
            
            if (mStatusChangeLister != null) {
                mStatusChangeLister.onStatusChange(true);
            }
        }
        else {
            mValueAnimator = ValueAnimator.ofInt(scrollX, 0);
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int value = (int) animation.getAnimatedValue();
                    
                    scrollTo(value, 0);
                }
            });
            
            mValueAnimator.setDuration(mAnimDuring);
            mValueAnimator.start();
            
            if (mStatusChangeLister != null) {
                mStatusChangeLister.onStatusChange(false);
            }
        }
    }

最后貼上左滑刪除容器的完整代碼:

/**
 * @author luowang
 * @date 2020-08-19 17:31
 * 左滑刪除View
 */
public class LeftSlideView extends LinearLayout {
    
    /**
     * tag
     */
    public static final String TAG = "LeftSlideView";
    
    /**
     * 上下文
     */
    private Context mContext;
    
    
    /**
     * 最小觸摸距離
     */
    private int mTouchSlop;
    
    
    /**
     * 右邊可滑動(dòng)距離
     */
    private int mRightCanSlide;
    
    
    /**
     * 按下x
     */
    private float mInitX;
    
    /**
     * 按下y
     */
    private float mInitY;
    
    
    /**
     * 屬性動(dòng)畫
     */
    private ValueAnimator mValueAnimator;
    
    
    /**
     * 動(dòng)畫時(shí)長(zhǎng)
     */
    private int mAnimDuring = 200;
    
    /**
     * 刪除按鈕的長(zhǎng)度
     */
    private int mDelLength = 76;
    
    /**
     * ViewPager
     */
    private ViewPager mViewPager;
    
    /**
     * RecyclerView
     */
    private RecyclerView mRecyclerView;
    
    /** CardView */
    private CardView mCardView;
    
    /** 是否重新計(jì)算 */
    private boolean isReCompute = true;
    
    
    /** 狀態(tài)監(jiān)聽 */
    private OnDelViewStatusChangeLister mStatusChangeLister;
    
    /**
     * 內(nèi)容區(qū)域View
     */
    private View mContentView;
    
    /**
     * 菜單區(qū)域View
     */
    private View mMenuView;
    
    
    
    public LeftSlideView(Context context) {
        this(context, null);
    }
    
    public LeftSlideView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
    
    public LeftSlideView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        
        init();
    }
    
    
    /**
     * 初始化
     */
    private void init() {
        mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
        mRightCanSlide = DPIUtil.dip2px(mContext, mDelLength);
        setBackgroundColor(Color.TRANSPARENT);
        // 水平布局
        setOrientation(LinearLayout.HORIZONTAL);
        initView();
    }
    
    /**
     * 設(shè)置內(nèi)容區(qū)域
     * @param contentView
     */
    public void addContentView(View contentView) {
        this.mContentView = contentView;
        this.mContentView.setTag("contentView");
        
        View cv = findViewWithTag("contentView");
        if (cv != null) {
            this.removeView(cv);
        }
        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
        );
        this.addView(this.mContentView, layoutParams);
    }
    
    /**
     * 設(shè)置右邊菜單區(qū)域
     */
    public void addMenuView(View menuView) {
        this.mMenuView = menuView;
        this.mMenuView.setTag("menuView");
        
        View mv = findViewWithTag("menuView");
        if (mv != null) {
            this.removeView(mv);
        }
        LayoutParams layoutParams = new LayoutParams(mRightCanSlide, ViewGroup.LayoutParams.MATCH_PARENT);
        this.addView(this.mMenuView, layoutParams);
    }
    
    
    /**
     * 設(shè)置Viewpager
     */
    public void setViewPager(ViewPager viewPager) {
        mViewPager = viewPager;
    }
    
    /**
     * 設(shè)置RecyclerView
     */
    public void setRecyclerView(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
    }
    
    /** 設(shè)置CardView */
    public void setCardView(CardView cardView) {
        mCardView = cardView;
    }
    
    /** 設(shè)置狀態(tài)監(jiān)聽 */
    public void setStatusChangeLister(OnDelViewStatusChangeLister statusChangeLister) {
        mStatusChangeLister = statusChangeLister;
    }
    
    /**
     * 初始化View
     */
    private void initView() {
        
    
    
    }
    
    
    /**
     * 攔截觸摸事件
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        
        int actionMasked = ev.getActionMasked();
        
        Log.e(TAG, "onInterceptTouchEvent: actionMasked = " + actionMasked);
        
        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                mInitX = ev.getRawX() + getScrollX();
                mInitY = ev.getRawY();
                clearAnim();
                
                if (mViewPager != null) {
                    mViewPager.requestDisallowInterceptTouchEvent(true);
                }
                
                if (mCardView != null) {
                    mCardView.requestDisallowInterceptTouchEvent(true);
                }
                
                break;
            
            case MotionEvent.ACTION_MOVE:
                
                if (mInitX - ev.getRawX() < 0) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                    
                    // 阻止ViewPager攔截事件
                    if (mViewPager != null) {
                        mViewPager.requestDisallowInterceptTouchEvent(true);
                    }
                    
                    return false;
                }
                
                // y軸方向上達(dá)到滑動(dòng)最小距離, x 軸未達(dá)到
                if (Math.abs(ev.getRawY() - mInitY) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) > Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                    
                    return false;
                    
                }
                
                // x軸方向達(dá)到了最小滑動(dòng)距離,y軸未達(dá)到
                if (Math.abs(mInitX - ev.getRawX() - getScrollX()) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) <= Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 阻止父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(true);
                        isReCompute = false;
                    }
                    
                    return true;
                }
                
                break;
            
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                
                if (mRecyclerView != null) {
                    mRecyclerView.requestDisallowInterceptTouchEvent(false);
                    isReCompute = true;
                }
                break;
            default:
                break;
        }
        
        return super.onInterceptTouchEvent(ev);
    }
    
    /**
     * 處理觸摸事件
     * 需要注意何時(shí)處理左滑,何時(shí)不處理
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        
        int actionMasked = ev.getActionMasked();
        
        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                mInitX = ev.getRawX() + getScrollX();
                mInitY = ev.getRawY();
                clearAnim();
                
                if (mViewPager != null) {
                    mViewPager.requestDisallowInterceptTouchEvent(true);
                }
                
                if (mCardView != null) {
                    mCardView.requestDisallowInterceptTouchEvent(true);
                }
                
                break;
            
            case MotionEvent.ACTION_MOVE:
                
                if (mInitX - ev.getRawX() < 0) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                    
                    // 阻止ViewPager攔截事件
                    if (mViewPager != null) {
                        mViewPager.requestDisallowInterceptTouchEvent(true);
                        isReCompute = false;
                    }
                }
                
                // y軸方向上達(dá)到滑動(dòng)最小距離, x 軸未達(dá)到
                if (Math.abs(ev.getRawY() - mInitY) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) > Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 讓父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(false);
                        isReCompute = false;
                    }
                }
                
                // x軸方向達(dá)到了最小滑動(dòng)距離,y軸未達(dá)到
                if (Math.abs(mInitX - ev.getRawX() - getScrollX()) >= mTouchSlop
                        && Math.abs(ev.getRawY() - mInitY) <= Math.abs(mInitX - ev.getRawX() - getScrollX())) {
                    
                    // 阻止父級(jí)容器攔截
                    if (mRecyclerView != null && isReCompute) {
                        mRecyclerView.requestDisallowInterceptTouchEvent(true);
                        isReCompute = false;
                    }
                }
                
                
                /** 如果手指移動(dòng)距離超過最小距離 */
                float translationX = mInitX - ev.getRawX();
                
                // 如果滑動(dòng)距離已經(jīng)大于右邊可伸縮的距離后, 應(yīng)該重新設(shè)置initx
                if (translationX > mRightCanSlide) {
                    mInitX = ev.getRawX() + mRightCanSlide;
                    
                }
                
                // 如果互動(dòng)距離小于0,那么重新設(shè)置初始位置initx
                if (translationX < 0) {
                    mInitX = ev.getRawX();
                }
                
                translationX = translationX > mRightCanSlide ? mRightCanSlide : translationX;
                translationX = translationX < 0 ? 0 : translationX;
                
                // 向左滑動(dòng)
                if (translationX <= mRightCanSlide && translationX >= 0) {
                    
                    scrollTo((int) translationX, 0);
                    
                    return true;
                }
                
                break;
            
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                
                if (mRecyclerView != null) {
                    mRecyclerView.requestDisallowInterceptTouchEvent(false);
                    isReCompute = true;
                }
                
                upAnim();
                
                return true;
                
                default:
                    break;
        }
        
        return true;
    }
    
    
    /**
     * 清除動(dòng)畫
     */
    private void clearAnim() {
        if (mValueAnimator == null) {
            return;
        }
        
        mValueAnimator.end();
        mValueAnimator.cancel();
        mValueAnimator = null;
    }
    
    
    /**
     * 手指抬起執(zhí)行動(dòng)畫
     */
    private void upAnim() {
        int scrollX = getScrollX();
        
        if (scrollX == mRightCanSlide || scrollX == 0) {
            
            if (mStatusChangeLister != null) {
                mStatusChangeLister.onStatusChange(scrollX == mRightCanSlide);
            }
            
            return;
        }
        
        clearAnim();
        
        // 如果顯出一半松開手指,那么自動(dòng)完全顯示。否則完全隱藏
        if (scrollX >= mRightCanSlide / 2) {
            mValueAnimator = ValueAnimator.ofInt(scrollX, mRightCanSlide);
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int value = (int) animation.getAnimatedValue();
                    
                    scrollTo(value, 0);
                }
            });
            
            mValueAnimator.setDuration(mAnimDuring);
            mValueAnimator.start();
            
            if (mStatusChangeLister != null) {
                mStatusChangeLister.onStatusChange(true);
            }
        }
        else {
            mValueAnimator = ValueAnimator.ofInt(scrollX, 0);
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int value = (int) animation.getAnimatedValue();
                    
                    scrollTo(value, 0);
                }
            });
            
            mValueAnimator.setDuration(mAnimDuring);
            mValueAnimator.start();
            
            if (mStatusChangeLister != null) {
                mStatusChangeLister.onStatusChange(false);
            }
        }
    }
    
    /**
     * 重置
     */
    public void resetDelStatus() {
        
        int scrollX = getScrollX();
        
        if (scrollX == 0) {
            return;
        }
        
        clearAnim();
        
        mValueAnimator = ValueAnimator.ofInt(scrollX, 0);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                
                scrollTo(value, 0);
            }
        });
        
        mValueAnimator.setDuration(mAnimDuring);
        mValueAnimator.start();
    }
    
    /**
     * 刪除按鈕狀態(tài)變化監(jiān)聽
     */
    public interface OnDelViewStatusChangeLister {
        
        /**
         * 狀態(tài)變化監(jiān)聽
         * @param show  是否正在顯示
         */
        void onStatusChange(boolean show);
    }
    
}

完整DEMO直通車:https://github.com/wwluo14/LeftSlideEdit

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容