迷你轻量级全方向完美滑动处理侧滑控件SlideLayout

来源:互联网 发布:php soap添加header 编辑:程序博客网 时间:2024/04/23 17:26

纯手工超级迷你轻量级全方向完美滑动处理侧滑控件(比官方 support v4 包 SlidingPaneLayout 控件更加 Q 迷你,累计代码不足 300 行),支持上下左右有各种侧拉,可配置侧拉松手临界距离,支持单独使用、ListView、GridView、RecycleView、ScrollView、ViewPager 等各种嵌套(作为 item 使用或者作为以上所有控件的父容器使用),具体不同配置展示效果如下图。

like SlidingPaneLayout, all direction support.
import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.widget.Scroller;/** * like SlidingPaneLayout, all direction support. */public class SlideLayout extends ViewGroup {    public static final int STATE_CLOSE = 0;    public static final int STATE_SLIDING = 1;    public static final int STATE_OPEN = 2;    private static final int SLIDE_RIGHT = 0;    private static final int SLIDE_LEFT = 1;    private static final int SLIDE_TOP = 2;    private static final int SLIDE_BOTTOM = 3;    private View mContentView;    private View mSlideView;    private Scroller mScroller;    private int mLastX = 0;    private int mLastY = 0;    private int mSlideCriticalValue = 0;    private boolean mIsScrolling = false;    private int mSlideDirection;    public SlideLayout(Context context) {        this(context, null);    }    public SlideLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SlideLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context, attrs);    }    private void init(Context context, AttributeSet attrs) {        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SlideLayout);        mSlideDirection = typedArray.getInt(R.styleable.SlideLayout_slideDirection, SLIDE_RIGHT);        mSlideCriticalValue = typedArray.getDimensionPixelSize(R.styleable.SlideLayout_slideCriticalValue, 0);        typedArray.recycle();        mScroller = new Scroller(context);    }    public int getSlideState() {        int retValue = STATE_CLOSE;        if (mIsScrolling) {            retValue = STATE_SLIDING;        } else {            int scrollOffset = (mSlideDirection == SLIDE_LEFT || mSlideDirection == SLIDE_RIGHT) ?                                getScrollX() : getScrollY();            retValue = (scrollOffset == 0) ? STATE_CLOSE : STATE_OPEN;        }        return retValue;    }    public void smoothCloseSlide() {        smoothScrollTo(0, 0);    }    public void smoothOpenSlide() {        switch (mSlideDirection) {            case SLIDE_RIGHT:                smoothScrollTo(mSlideView.getMeasuredWidth(), 0);                break;            case SLIDE_LEFT:                smoothScrollTo(-mSlideView.getMeasuredWidth(), 0);                break;            case SLIDE_TOP:                smoothScrollTo(0, -mSlideView.getMeasuredHeight());                break;            case SLIDE_BOTTOM:                smoothScrollTo(0, mSlideView.getMeasuredHeight());                break;        }    }    @Override    protected void onFinishInflate() {        super.onFinishInflate();        if (getChildCount() != 2) {            throw new IllegalArgumentException("SlideLayout only need contains two child (content and slide).");        }        mContentView = getChildAt(0);        mSlideView = getChildAt(1);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        measureChildren(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        mContentView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());        switch (mSlideDirection) {            case SLIDE_LEFT:                mSlideView.layout(-mSlideView.getMeasuredWidth(), 0, 0, getMeasuredHeight());                break;            case SLIDE_RIGHT:                mSlideView.layout(getMeasuredWidth(), 0,                        mSlideView.getMeasuredWidth() + getMeasuredWidth(), getMeasuredHeight());                break;            case SLIDE_TOP:                mSlideView.layout(0, -mSlideView.getMeasuredHeight(), getMeasuredWidth(), 0);                break;            case SLIDE_BOTTOM:                mSlideView.layout(0, getMeasuredHeight(),                        getMeasuredWidth(), mSlideView.getMeasuredHeight() + getMeasuredHeight());                break;        }    }    @Override    public boolean onInterceptTouchEvent(MotionEvent event) {        return mIsScrolling || super.onInterceptTouchEvent(event);    }    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        int eventX = (int) event.getX();        int eventY = (int) event.getY();        int scrollX = getScrollX();        int scrollY = getScrollY();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                mLastX = (int) event.getX();                mLastY = (int) event.getY();                mIsScrolling = false;                //Maybe child not set OnClickListener, so ACTION_DOWN need to return true and use super.                super.dispatchTouchEvent(event);                return true;            case MotionEvent.ACTION_MOVE:                int offsetX = eventX - mLastX;                int offsetY = eventY - mLastY;                int directionMoveOffset = 0;                if (mSlideDirection == SLIDE_LEFT || mSlideDirection == SLIDE_RIGHT) {                    directionMoveOffset = Math.abs(offsetX) - Math.abs(offsetY);                } else {                    directionMoveOffset = Math.abs(offsetY) - Math.abs(offsetX);                }                if (!mIsScrolling && directionMoveOffset < ViewConfiguration.getTouchSlop()) {                    break;                }                getParent().requestDisallowInterceptTouchEvent(true);                mIsScrolling = true;                int newScrollX = 0;                int newScrollY = 0;                switch (mSlideDirection) {                    case SLIDE_RIGHT:                        newScrollX = scrollX - offsetX;                        if (newScrollX < 0) {                            newScrollX = 0;                        } else if (newScrollX > mSlideView.getMeasuredWidth()) {                            newScrollX = mSlideView.getMeasuredWidth();                        }                        break;                    case SLIDE_LEFT:                        newScrollX = scrollX - offsetX;                        if (newScrollX < -mSlideView.getMeasuredWidth()) {                            newScrollX = -mSlideView.getMeasuredWidth();                        } else if (newScrollX > 0) {                            newScrollX = 0;                        }                        break;                    case SLIDE_TOP:                        newScrollY = scrollY - offsetY;                        if (newScrollY < -mSlideView.getMeasuredHeight()) {                            newScrollY = -mSlideView.getMeasuredHeight();                        } else if (newScrollY > 0) {                            newScrollY = 0;                        }                        break;                    case SLIDE_BOTTOM:                        newScrollY = scrollY - offsetY;                        if (newScrollY < 0) {                            newScrollY = 0;                        } else if (newScrollY > mSlideView.getMeasuredHeight()) {                            newScrollY = mSlideView.getMeasuredHeight();                        }                        break;                }                scrollTo(newScrollX, newScrollY);                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                mIsScrolling = false;                getParent().requestDisallowInterceptTouchEvent(false);                int finalScrollX = 0;                int finalScrollY = 0;                switch (mSlideDirection) {                    case SLIDE_RIGHT:                        if (scrollX > getSlideCriticalValue()) {                            finalScrollX = mSlideView.getMeasuredWidth();                        }                        break;                    case SLIDE_LEFT:                        if (scrollX < -getSlideCriticalValue()) {                            finalScrollX = -mSlideView.getMeasuredWidth();                        }                        break;                    case SLIDE_TOP:                        if (scrollY < -getSlideCriticalValue()) {                            finalScrollY = -mSlideView.getMeasuredHeight();                        }                        break;                    case SLIDE_BOTTOM:                        if (scrollY > getSlideCriticalValue()) {                            finalScrollY = mSlideView.getMeasuredHeight();                        }                        break;                }                smoothScrollTo(finalScrollX, finalScrollY);                break;        }        mLastX = eventX;        mLastY = eventY;        return super.dispatchTouchEvent(event);    }    //TODO  when mSlideCriticalValue != 0, slide critical need fix.    private int getSlideCriticalValue() {        if (mSlideDirection == SLIDE_LEFT || mSlideDirection == SLIDE_RIGHT) {            if (mSlideCriticalValue == 0) {                mSlideCriticalValue = mSlideView.getMeasuredWidth() / 2;            }        } else {            if (mSlideCriticalValue == 0) {                mSlideCriticalValue = mSlideView.getMeasuredHeight() / 2;            }        }        return mSlideCriticalValue;    }    private void smoothScrollTo(int destX, int destY) {        int scrollX = getScrollX();        int deltaX = destX - scrollX;        int scrollY = getScrollY();        int deltaY = destY - scrollY;        mScroller.startScroll(scrollX, scrollY, deltaX, deltaY,                (int) (Math.abs(Math.sqrt(deltaX*deltaX + deltaY*deltaY)) * 3));        postInvalidate();    }    @Override    public void computeScroll() {        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            postInvalidate();        }    }}


自定义属性:
<declare-styleable name="SlideLayout">        <attr name="slideDirection">            <enum name="fromRight" value="0"/>            <enum name="fromLeft" value="1"/>            <enum name="fromTop" value="2"/>            <enum name="fromBottom" value="3"/>        </attr>        <attr name="slideCriticalValue" format="dimension"/>    </declare-styleable>


like SlidingPaneLayout, but this used to mini lib and only support right slide.
used to no support v4 import.

import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.LinearLayout;import android.widget.Scroller;/** * like SlidingPaneLayout, but this used to mini lib and only support right slide. * used to no support v4 import. */public class MiniSlideRightLayout extends LinearLayout {    public static final int STATE_CLOSE = 0;    public static final int STATE_SLIDING = 1;    public static final int STATE_OPEN = 2;    private View mContentView;    private View mSlideView;    private Scroller mScroller;    private int mLastX = 0;    private int mLastY = 0;    private int mSlideSensitiveWidth = 0;    private boolean mIsScrolling = false;    public MiniSlideRightLayout(Context context) {        this(context, null);    }    public MiniSlideRightLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MiniSlideRightLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context, attrs);    }    private void init(Context context, AttributeSet attrs) {        setOrientation(HORIZONTAL);        mScroller = new Scroller(context);    }    @Override    protected void onFinishInflate() {        super.onFinishInflate();        if (getChildCount() != 2) {            throw new IllegalArgumentException("SlideLayout only need contains two child (content and slide).");        }        mContentView = getChildAt(0);        mSlideView = getChildAt(1);    }    public int getSlideState() {        int retValue = STATE_CLOSE;        if (mIsScrolling) {            retValue = STATE_SLIDING;        } else {            retValue = (getScrollX() == 0) ? STATE_CLOSE : STATE_OPEN;        }        return retValue;    }    public void smoothCloseSlide() {        smoothScrollTo(0, 0);    }    public void smoothOpenSlide() {        smoothScrollTo(mSlideView.getMeasuredWidth(), 0);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent event) {        return mIsScrolling || super.onInterceptTouchEvent(event);    }    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        int eventX = (int) event.getX();        int eventY = (int) event.getY();        int scrollX = getScrollX();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                mLastX = (int) event.getX();                mLastY = (int) event.getY();                mIsScrolling = false;                //Maybe child not set OnClickListener, so ACTION_DOWN need to return true and use super.                super.dispatchTouchEvent(event);                return true;            case MotionEvent.ACTION_MOVE:                int offsetX = eventX - mLastX;                int offsetY = eventY - mLastY;                if (Math.abs(offsetX) - Math.abs(offsetY) < 1) {                    break;                }                getParent().requestDisallowInterceptTouchEvent(true);                mIsScrolling = true;                int newScrollX = scrollX - offsetX;                if (newScrollX < 0) {                    newScrollX = 0;                } else if (newScrollX > mSlideView.getMeasuredWidth()) {                    newScrollX = mSlideView.getMeasuredWidth();                }                scrollTo(newScrollX, 0);                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                mIsScrolling = false;                getParent().requestDisallowInterceptTouchEvent(false);                int finalScrollX = 0;                mSlideSensitiveWidth = mSlideView.getMeasuredWidth() / 2;                if (scrollX > mSlideSensitiveWidth) {                    finalScrollX = mSlideView.getMeasuredWidth();                }                smoothScrollTo(finalScrollX, 0);                break;        }        mLastX = eventX;        mLastY = eventY;        return super.dispatchTouchEvent(event);    }    private void smoothScrollTo(int destX, int destY) {        int scrollX = getScrollX();        int deltaX = destX - scrollX;        int scrollY = getScrollY();        int deltaY = destY - scrollY;        mScroller.startScroll(scrollX, scrollY, deltaX, deltaY,                (int) (Math.abs(Math.sqrt(deltaX*deltaX + deltaY*deltaY)) * 3));        postInvalidate();    }    @Override    public void computeScroll() {        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            postInvalidate();        }    }}


https://github.com/yanbober/SlideLayout
0 0
原创粉丝点击