左滑显示删除按钮

public class CleerScrollHorizontalView extends CleerDividerLinearLayout {
    private static final String TAG = "Cleer.ScrollView";

    private static final boolean DEBUG = true;

    private static final int MAX_DRAG_LENGTH = 316;
    private static final int START_SCROLL_LENGTH = MAX_DRAG_LENGTH / 2;
    private static int DRAG_NOT_CLICK_SIGN_LENGTH;

    private static final int SCROLL_ANIM_DURATION = 850;

    private static final int COLOR_RED_NORMAL = 0xffe70909;
    private static final int COLOR_RED_PRESSED = 0x5fe70909;

    private Scroller mScroller;
    private Paint deleteBgPaint;
    private Paint deleteIconPaint;
    private Bitmap deleteBitmap;
    private int layoutWidth;
    private int layoutHeight;
    private int deleteWidth;
    private int deleteHeight;

    private boolean deleteClickSign = false;
    private boolean itemExceptDeleteClickSign = false;
    private boolean itemClickSign = false;
    private boolean deleteClickAnimation = false;
    private boolean needShowDeleteView = false;

    private int currX;
    private int prevX;
    private int origX;

    private boolean intercept;

    //For log
    private String logTag = TAG;
    private OnDeleteClickListener listener;
    private OnClickListener onClickListener;

    public void setLogTag(String tag) {
        logTag = tag;
    }

    public interface OnDeleteClickListener {
        void onClick();
    }

    public void setOnDeleteClickListener(OnDeleteClickListener listener) {
        this.listener = listener;
    }

    public void setOnClickListener(OnClickListener listener) {
        onClickListener = listener;
    }

    public CleerScrollHorizontalView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context, new DecelerateInterpolator());
        deleteBgPaint = new Paint();
        deleteIconPaint = new Paint();
        deleteBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_item_delete);

        DRAG_NOT_CLICK_SIGN_LENGTH = ViewConfiguration.get(context).getScaledTouchSlop();

        //Force layout to invoke onDraw
        setWillNotDraw(false);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        layoutWidth = this.getMeasuredWidth();
        layoutHeight = this.getMeasuredHeight();
        deleteWidth = deleteBitmap.getWidth();
        deleteHeight = deleteBitmap.getHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        deleteBgPaint.setColor(deleteClickAnimation ? COLOR_RED_PRESSED : COLOR_RED_NORMAL);
        //Draw deleteBg
        canvas.drawRect(layoutWidth, 0, layoutWidth + MAX_DRAG_LENGTH, layoutHeight, deleteBgPaint);
        //Draw deleteIcon
        int deleteLeft = layoutWidth + (MAX_DRAG_LENGTH - deleteWidth) / 2;
        int deleteTop = (layoutHeight - deleteHeight) / 2;
        canvas.drawBitmap(deleteBitmap, deleteLeft, deleteTop, deleteIconPaint);
    }

    private boolean isTouchPointInDeleteView(int x, int y) {
        return x > layoutWidth && x <= layoutWidth + MAX_DRAG_LENGTH
                && y >= 0 && y <= layoutHeight;
    }

    private boolean isTouchPointInItemNotDeleteView(int x, int y) {
        return x >= 0 && x <= layoutWidth
                && y >= 0 && y <= layoutHeight;
    }

    /** Hide the deleteView */
    private void hideDeleteView() {
        startScroll(getScrollX(), 0, -getScrollX(), 0, SCROLL_ANIM_DURATION);
    }

    /** Hide all the layouts except itself */
    private void triggerInitAllOthersLayouts() {
        if (getParent() instanceof ViewGroup) {
            ViewGroup parent = (ViewGroup) getParent();
            for (int i = 0; i < parent.getChildCount(); ++i) {
                View child = parent.getChildAt(i);
                if (child instanceof CleerScrollHorizontalView && !child.equals(this)) {
                    CleerScrollHorizontalView c = (CleerScrollHorizontalView) child;
                    c.hideDeleteView();
                }
            }
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                if (DEBUG)
                    Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_DOWN->" + ev.getX());

                triggerInitAllOthersLayouts();
                mScroller.forceFinished(true);

                origX = currX = prevX = (int) ev.getX();

                needShowDeleteView = false;
                deleteClickSign = isTouchPointInDeleteView((int) ev.getX() + getScrollX(), (int) ev.getY());
                itemExceptDeleteClickSign = !deleteClickSign;
                itemClickSign = true;
                //For deleteView rendering, type:ACTION_DOWN
                deleteClickAnimation = deleteClickSign;
                invalidate();

                intercept = false;

                break;
            }
            case MotionEvent.ACTION_MOVE: {
                if (DEBUG) Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_MOVE");

                //Scroll animation
                currX = (int) ev.getX();
                if (intercept) {
                    int dOffset = -(currX - prevX);
                    if (getScrollX() + dOffset < 0) {
                        if (DEBUG)
                            Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_MOVE" + ", move type one");
                        scrollTo(0, 0);
                    } else if (getScrollX() + dOffset > MAX_DRAG_LENGTH) {
                        if (DEBUG)
                            Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_MOVE" + ", move type two");
                        scrollTo(MAX_DRAG_LENGTH, 0);
                    } else {
                        if (DEBUG)
                            Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_MOVE" + ", move type three->" + dOffset);
                        scrollBy(dOffset, 0);
                    }
                }

                //For deleteView rendering, type:ACTION_MOVE
                deleteClickAnimation = isTouchPointInDeleteView((int) ev.getX() + getScrollX(), (int) ev.getY());
                invalidate();

                if (Math.abs(currX - origX) >= DRAG_NOT_CLICK_SIGN_LENGTH) {
                    //Disallow parent to intercept MotionEvent
                    getParent().requestDisallowInterceptTouchEvent(true);
                    intercept = true;
                }

                prevX = currX;

                break;
            }
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP: {
                if (DEBUG) Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_UP");
                currX = (int) ev.getX();

                if (Math.abs(currX - origX) >= DRAG_NOT_CLICK_SIGN_LENGTH) {
                    itemClickSign = false;
                    itemExceptDeleteClickSign = false;
                }
                if (deleteClickSign && isTouchPointInDeleteView((int) ev.getX() + getScrollX(), (int) ev.getY())) {
                    if (DEBUG) Log.v(TAG, "logTag->" + logTag + " deleteView clicked");
                    hideDeleteView();
                    if (listener != null) {
                        listener.onClick();
                    }
                    itemClickSign = true;
                }

                //For deleteView rendering, type:ACTION_UP
                deleteClickAnimation = false;
                invalidate();

                //Scroll animation
                if (getScrollX() > 0 && getScrollX() < START_SCROLL_LENGTH) {
                    needShowDeleteView = false;
                }
                if (getScrollX() > START_SCROLL_LENGTH) {
                    needShowDeleteView = true;
                }

                if (currX > origX) {
                    needShowDeleteView = false;
                }
                if (needShowDeleteView) {
                    if (DEBUG)
                        Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_UP" + ", up to changed");
                    mScroller.forceFinished(true);
                    startScroll(getScrollX(), 0, MAX_DRAG_LENGTH - getScrollX(), 0, SCROLL_ANIM_DURATION);
                } else {
                    if (DEBUG)
                        Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_UP" + ", up to origin2");
                    mScroller.forceFinished(true);
                    startScroll(getScrollX(), 0, -getScrollX(), 0, SCROLL_ANIM_DURATION);
                }
                if (needShowDeleteView && itemClickSign) {
                    if (DEBUG)
                        Log.v("dispatchTouchEvent", "logTag->" + logTag + ", ACTION_UP" + ", up to origin3");
                    mScroller.forceFinished(true);
                    startScroll(getScrollX(), 0, -getScrollX(), 0, SCROLL_ANIM_DURATION);
                }

                break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (!itemClickSign) {
            return true;
        }
        return super.onInterceptTouchEvent(ev) || intercept;
    }

    @Override
    public boolean performClick() {
        boolean r = super.performClick();
        if (onClickListener != null) {
            onClickListener.onClick(this);
            return true;
        }
        return r;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (!intercept)
            super.onTouchEvent(ev);
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            if (itemExceptDeleteClickSign
                    && isTouchPointInItemNotDeleteView((int) ev.getX() + getScrollX(), (int) ev.getY())
                    && !isTouchPointInDeleteView((int) ev.getX() + getScrollX(), (int) ev.getY())) {
                if (DEBUG) Log.v(TAG, "logTag->" + logTag + " itemExceptDeleteView clicked");
                performClick();
                itemExceptDeleteClickSign = false;
            }
        }
        return true;
    }

    private void startScroll(int startX, int startY, int dx, int dy, int duration) {
        int readDuration = Math.abs((int) (1.0f * duration / MAX_DRAG_LENGTH * dx));
        mScroller.startScroll(startX, startY, dx, dy, readDuration);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), 0);
            postInvalidate();
        }
    }
}

复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值