自定义控件之(上下左右)侧滑页面

1.效果图(还有顶部及底部就省略)

2.代码实现

 

1)java代码
/**
 * Created by 刘强lq
 *
 * 自定义控件 上下左右滑出界面
 */
public class SliderPager extends FrameLayout {

    //右边侧滑
    public static final int MODEL_RIGHT = 0;

    //左边侧滑
    public static final int MODEL_LEFT = 1;

    //顶部滑出
    public static final int MODEL_TOP = 2;

    //低部滑出
    public static final int MODEL_BUTTOM = 3;

    /**
     * 存放主页内容的View
     */
    private ViewGroup mContentView;
    /**
     * 存放侧滑栏内容的View
     */
    private ViewGroup mSiderView;
    /**
     * 存放侧滑栏内容View宽
     */
    private int mSiderViewWidth;
    /**
     * 存放侧滑栏内容View高
     */
    private int mSiderViewHeight;
    /**
     * SliderPager布局的宽
     */
    private int mSliderPagerWidth;
    /**
     * SliderPager布局的高
     */
    private int mSliderPagerHeight;
    /**
     * 侧滑栏显示的模式
     */
    private int mSlidingModel;
    /**
     * 显示部分
     */
    private int mSlidingShowLeftOrRightValue = 0;
    /**
     * 平滑者
     */
    private Scroller mScroller;

    /**
     * 侧滑页面是否打开 默认是关闭的状态
     */
    private boolean mIsOpenPager = false;

    /**
     * 如果mContentView中存在ViewPager的话 针对于左右滑动
     */
    private ViewPager mViewPager;

    /**
     * 记录当前mViewPager选中的第几个item(如果存在ViewPager的话)
     */
    private int mCurrentViewPagerPosition = 0;

    /**
     * 如果mSiderView中存在ListView的话 针对于上下滑动
     */
    private ListView mListView;

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

    public SliderPager(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SliderPager(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScroller = new Scroller(context);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SliderPager);
        int indexCount = typedArray.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
            int index = typedArray.getIndex(i);
            switch (index) {
                case R.styleable.SliderPager_slidingModel:
                    mSlidingModel = typedArray.getInt(index, 0);
                    break;
                case R.styleable.SliderPager_slidingShowLeftOrRight:
                    mSlidingShowLeftOrRightValue = typedArray.getDimensionPixelSize(index, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
                default:
                    break;
            }
        }
        typedArray.recycle();
    }

    /**
     * 孩子View的定位
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        switch (mSlidingModel) {
            case 0: //侧滑在右边
                mSiderView.layout(mSliderPagerWidth, 0, mSliderPagerWidth + mSiderViewWidth, mSiderViewHeight);
                break;
            case 1:  //侧滑在左边
                mSiderView.layout(0 - mSiderViewWidth, 0, 0, mSiderViewHeight);
                break;
            case 2://侧滑在上边
                mSiderView.layout(0, 0 - mSiderViewHeight, mSliderPagerWidth, 0);
                break;
            case 3://侧滑在下边
                mSiderView.layout(0, mSiderViewHeight, mSliderPagerWidth, mSliderPagerHeight + mSiderViewHeight);
                break;
            default:
                break;
        }
    }

    /**
     * 获取宽高
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mSiderViewWidth = mSiderView.getMeasuredWidth() - mSlidingShowLeftOrRightValue;
        mSiderViewHeight = mSiderView.getMeasuredHeight();
        mSliderPagerWidth = getMeasuredWidth();
        mSliderPagerHeight = getMeasuredHeight();
    }

    /**
     * 加载布局完后回调
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mContentView = (ViewGroup) getChildAt(0);
        //如果mContentView中包含ViewPager 取出
        for (int i = 0; i < mContentView.getChildCount(); i++) {
            View childView = mContentView.getChildAt(i);
            if (childView instanceof ViewPager) {
                mViewPager = (ViewPager) childView;
            }
        }
        mSiderView = (ViewGroup) getChildAt(1);
        //如果mSiderView中包含ListView 取出
        for (int i = 0; i < mSiderView.getChildCount(); i++) {
            View childView = mSiderView.getChildAt(i);
            if (childView instanceof ListView) {
                mListView = (ListView) childView;
            }
        }
        mContentView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // Log.e("liuqiang", "isOpenPager:" + mIsOpenPager);
                if (mIsOpenPager) {
                    closeSlidePager();
                }
            }
        });
        if (mViewPager != null) {
            mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                    mCurrentViewPagerPosition = position;
                }

                @Override
                public void onPageSelected(int position) {
                    mCurrentViewPagerPosition = position;
                }

                @Override
                public void onPageScrollStateChanged(int state) {
                }
            });
        }
    }

    /**
     * 记录手指按下开始的X轴的位置
     */
    private float mStartX;
    /**
     * 记录手指按下开始的Y轴的位置
     */
    private float mStartY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mStartX = event.getX();
                mStartY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float endX = event.getX();
                float endY = event.getY();
                //得到X轴的偏移量
                int distanceX = (int) (endX - mStartX);
                int scrollToX = getScrollX() - distanceX;
                //得到Y轴的偏移量
                int distanceY = (int) (endY - mStartY);
                int scrollToY = getScrollY() - distanceY;
                switch (mSlidingModel) {
                    case 0://从右往左
                        if (scrollToX < -50) {
                            scrollToX = 0;
                        } else if (scrollToX > mSiderViewWidth) {
                            scrollToX = mSiderViewWidth;
                        }
                        scrollTo(scrollToX, getScrollY());
                        break;
                    case 1://从左往右
                        if (scrollToX > 50) {
                            scrollToX = 0;
                        } else if (scrollToX < -mSiderViewWidth) {
                            scrollToX = -mSiderViewWidth;
                        }

                        scrollTo(scrollToX, getScrollY());
                        break;
                    case 2://从上往下
                        if (scrollToY > 50) {
                            scrollToY = 0;
                        } else if (scrollToY < -mSiderViewHeight) {
                            scrollToY = -mSiderViewHeight;
                        }
                        scrollTo(getScrollX(), scrollToY);
                        break;
                    case 3://从下往上
                        if (scrollToY < -50) {
                            scrollToY = 0;
                        } else if (scrollToY > mSiderViewHeight) {
                            scrollToY = mSiderViewHeight;
                        }
                        scrollTo(getScrollX(), scrollToY);
                        break;
                    default:
                        break;
                }
                mStartX = endX;
                mStartY = endY;
                break;
            case MotionEvent.ACTION_UP:
                int scrollX = getScrollX();
                int scrollY = getScrollY();
                switch (mSlidingModel) {
                    case 0:
                        if (scrollX > mSiderViewWidth / 2) {
                            mScroller.startScroll(getScrollX(), getScrollY(), mSiderViewWidth - getScrollX(), getScrollY()
                                    , Math.abs(mSiderViewWidth - getScrollX()));
                            mIsOpenPager = true;
                            mIntercept = false;
                        } else {
                            mScroller.startScroll(getScrollX(), getScrollY(), 0 - getScrollX(), getScrollY(), Math.abs(0 - getScrollX()));
                            mIsOpenPager = false;
                            mIntercept = false;
                        }
                        break;
                    case 1:
                        if (scrollX < -(mSiderViewWidth / 2)) {
                            mScroller.startScroll(getScrollX(), getScrollY(), -mSiderViewWidth - getScrollX(), getScrollY(),
                                    Math.abs(-mSiderViewWidth - getScrollX()));
                            mIsOpenPager = true;
                            mIntercept = false;
                        } else {
                            mScroller.startScroll(getScrollX(), getScrollY(), 0 - getScrollX(), getScrollY(), Math.abs(0 - getScrollX()));
                            mIsOpenPager = false;
                            mIntercept = false;
                        }
                        break;
                    case 2:
                        if (scrollY < -(mSiderViewHeight / 2)) {
                            mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), -mSiderViewHeight - getScrollY(),
                                    Math.abs(-mSiderViewHeight - getScrollY()));
                            mIsOpenPager = true;
                            mIntercept = false;
                        } else {
                            mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), 0 - getScrollY(), Math.abs(0 - getScrollY()));
                            mIsOpenPager = false;
                            mIntercept = false;
                        }
                        break;
                    case 3:
                        if (scrollY > mSiderViewHeight / 2) {
                            mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), mSiderViewHeight - getScrollY()
                                    , Math.abs(mSiderViewHeight - getScrollY()));
                            mIsOpenPager = true;
                            mIntercept = false;
                        } else {
                            mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), 0 - getScrollY(), Math.abs(0 - getScrollY()));
                            mIsOpenPager = false;
                            mIntercept = false;
                        }
                        break;
                    default:
                        break;
                }
                invalidate();
                break;
        }
        return onInterceptTouchEvent(event);
    }

    /**
     * mScrollerd的回调
     */
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }

    /**
     * 事件拦截 记录手指按下开始的X,Y轴的位置
     */
    private float mInterceptStartX;
    private float mInterceptStartY;

    /**
     * 事件是否拦截 默认不拦截
     */
    private boolean mIntercept = false;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mInterceptStartX = ev.getX();
                mInterceptStartY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float interceptEndX = ev.getX();
                float interceptEndY = ev.getY();
                int distanceX = (int) (interceptEndX - mInterceptStartX);
                int distanceY = (int) (interceptEndY - mInterceptStartY);

                //对每一个滑动的模式进行拦截判断
                switch (mSlidingModel) {
                    case 0: //从右滑出
                        if (mIsOpenPager) { //要关闭的时候
                            if (distanceX > 0) {
                                mIntercept = true;
                            } else if (distanceX < 0) {
                                mIntercept = false;
                            } else if (Math.abs(distanceY) > 50) {
                                mIntercept = false;
                            }
                        } else { //要打开的时候
                            if (distanceX > 0) {
                                mIntercept = false;
                            } else if (distanceX < 0) {
                                if (mViewPager != null) {
                                    if (mCurrentViewPagerPosition == mViewPager.getChildCount()) {
                                        mIntercept = true;
                                    } else {
                                        mIntercept = false;
                                    }
                                } else {
                                    mIntercept = true;
                                }
                            } else if (Math.abs(distanceY) > 50) {
                                mIntercept = false;
                            }
                        }

                        break;
                    case 1:
                        //左滑动的情况下处理事件的拦截
                        //对左滑动的页面中嵌套scrollView等等控件时的拦截
                        if (mIsOpenPager) { //要关闭的时候
                            if (distanceX > 0) {
                                mIntercept = false;
                            } else if (distanceX < 0) {
                                mIntercept = true;
                            } else if (Math.abs(distanceY) > 50) {
                                mIntercept = true;
                            }
                        } else { //要打开的时候
                            if (distanceX > 0) {
                                if (mCurrentViewPagerPosition == 0) {
                                    mIntercept = true;
                                } else {
                                    mIntercept = false;
                                }
                            } else if (distanceX < 0) {
                                mIntercept = false;
                            } else if (Math.abs(distanceY) > 50) {
                                mIntercept = false;
                            }
                        }
                        break;
                    case 2: //顶部滑出
                        if (distanceY < 0) { //从下往上滑
                            if (mListView != null) {
                                if (mListView.getLastVisiblePosition() == (mListView.getCount() - 1) && mListView.getChildCount() > 0) {
                                    //判定滑动到了当前一屏显示的ListView最后个条目
                                    mIntercept = true;
                                } else {
                                    mIntercept = false;
                                }
                            }
                        } else {
                            mIntercept = false;
                        }
                        break;
                    case 3:
                        if (distanceY > 0) { //从上往下滑
                            if (mListView != null) {
                                if (mListView.getFirstVisiblePosition() == 0 && mListView.getChildCount() > 0) {
                                    //判定滑动到了当前一屏显示的ListView第一个条目
                                    mIntercept = true;
                                } else {
                                    mIntercept = false;
                                }
                            }
                        } else {
                            mIntercept = false;
                        }
                        break;
                }

                mInterceptStartX = interceptEndX;
                mInterceptStartY = interceptEndY;
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return mIntercept;
    }

    /**
     * 打开侧滑页面
     */
    public void openSlidePager() {
        switch (mSlidingModel) {
            case 0:
                mScroller.startScroll(getScrollX(), getScrollY(), mSiderViewWidth - getScrollX(), getScrollY()
                        , Math.abs(mSiderViewWidth - getScrollX()));
                break;
            case 1:
                mScroller.startScroll(getScrollX(), getScrollY(), -mSiderViewWidth - getScrollX(), getScrollY(),
                        Math.abs(-mSiderViewWidth - getScrollX()));
                break;
            case 2:
                mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), -mSiderViewHeight - getScrollY(),
                        Math.abs(-mSiderViewHeight - getScrollY()));
                break;
            case 3:
                mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), mSiderViewHeight - getScrollY()
                        , Math.abs(mSiderViewHeight - getScrollY()));
                break;
            default:
                break;
        }
        invalidate();
        mIsOpenPager = true;
    }

    /**
     * 关闭侧滑页面
     */
    public void closeSlidePager() {
        switch (mSlidingModel) {
            case 0:
                mScroller.startScroll(getScrollX(), getScrollY(), 0 - getScrollX(), getScrollY(),
                        Math.abs(0 - getScrollX()));
                invalidate();
                break;
            case 1:
                mScroller.startScroll(getScrollX(), getScrollY(), 0 - getScrollX(), getScrollY(), Math.abs(0 - getScrollX()));
                invalidate();
                break;
            case 2:
                mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), 0 - getScrollY(), Math.abs(0 - getScrollY()));
                invalidate();
                break;
            case 3:
                mScroller.startScroll(getScrollX(), getScrollY(), getScrollX(), 0 - getScrollY(), Math.abs(0 - getScrollY()));
                invalidate();
                break;
            default:
                break;
        }
        mIsOpenPager = false;
    }

    /**
     * 获取滑动方向
     *
     * @return
     */
    public int getSlidingModel() {
        return mSlidingModel;
    }

    /**
     * 设置滑动方向
     *
     * @param slidingModel
     */
    public void setSlidingModel(int slidingModel) {
        mSlidingModel = slidingModel;
        invalidate();
    }

    /**
     * 获取左右页面滑出留的的距离
     *
     * @return
     */
    public int getSlidingShowLeftOrRightValue() {
        return mSlidingShowLeftOrRightValue;
    }

    /**
     * 设置左右滑出页面留的的距离
     *
     * @param slidingShowLeftOrRightValue
     */
    public void setSlidingShowLeftOrRightValue(int slidingShowLeftOrRightValue) {
        mSlidingShowLeftOrRightValue = px2dp(slidingShowLeftOrRightValue);
        invalidate();
    }

    /**
     * 当前打开滑动页面的状态
     *
     * @return
     */
    public boolean isOpenPager() {
        return mIsOpenPager;
    }

    /**
     * 将px转化为dip
     *
     * @param pxValue
     * @return
     */
    private int px2dp(int pxValue) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                pxValue, getResources().getDisplayMetrics());
    }
}
 
2)属性
 
<declare-styleable name="SliderPager">
    <attr name="slidingModel" format="enum">
        <enum name="sliding_right" value="0"/>
        <enum name="sliding_left" value="1"/>
        <enum name="sliding_top" value="2"/>
        <enum name="sliding_buttom" value="3"/>
    </attr>
    <attr name="slidingShowLeftOrRight" format="dimension"/>
</declare-styleable>

 

由于时间问题,只能将就,先......

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值