自定义控件:Viewpager

来源:互联网 发布:土行孙网络加速登录 编辑:程序博客网 时间:2024/05/22 08:41

自定义控件:Viewpager

package com.itheima.myviewpager66;import android.content.Context;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.Scroller;/** * 自定义ViewPager *  * 1. 写一个类继承ViewGroup * 2. 重写onLayout方法, 保证孩子正常显示(一字排开) * 3. 重写onTouchEvent, 手势识别器(onScroll),scrollby * 4. 监听手指抬起事件,根据当前滑动后位置,确定下一个页面, scrollTo * 5. 防止pos过大 * 6. 平滑移动, Scroller, startScroll->computeScroll * 7. 增加RadioButton, 监听自定义viewpager页面切换(回调接口),更改raidoButton选中位置 * 8. 监听RadioButton切换事件, 更改页面 * 9. 增加测试页面(ScrollView) * 11. 重写onMeasure,测量每个孩子 * 12. 重写onInterceptTouchEvent, 在适当时机(水平滑动),中断事件传递 * @author Kevin * @date 2015-8-8 */public class MyViewPager extends ViewGroup {    // 手势识别器    private GestureDetector mDetector;    private Scroller mScroller;    public MyViewPager(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        initView();    }    public MyViewPager(Context context, AttributeSet attrs) {        super(context, attrs);        initView();    }    public MyViewPager(Context context) {        super(context);        initView();    }    private void initView() {        mDetector = new GestureDetector(getContext(),                new GestureDetector.SimpleOnGestureListener() {                    // 手势滑动                    @Override                    public boolean onScroll(MotionEvent e1, MotionEvent e2,                            float distanceX, float distanceY) {                        scrollBy((int) distanceX, 0);// 滑动x,y方向偏移一定距离, 相对位移                        // scrollTo(x, y);//绝对位移, 移动到确定的x,y坐标位置                        return super.onScroll(e1, e2, distanceX, distanceY);                    }                });        // 初始化滑动器        mScroller = new Scroller(getContext());    }    // 测量布局宽高    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        // 手动测量所有孩子的宽高, 解决测试页面无法展示的bug        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);        }        System.out.println("widthMeasureSpec:" + widthMeasureSpec);        System.out.println("heightMeasureSpec:" + heightMeasureSpec);        int size = MeasureSpec.getSize(widthMeasureSpec);        System.out.println("width:" + size);        int mode = MeasureSpec.getMode(widthMeasureSpec);        //MeasureSpec.AT_MOST; //wrap_content        //MeasureSpec.EXACTLY; //确定值 , 宽高写死, 100dp/ match_parent        //MeasureSpec.UNSPECIFIED;//没有指定宽高        System.out.println("mode:" + mode);    }    // 设置布局位置    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // 手动设置孩子们的位置, 保证一字排开        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            getChildAt(i).layout(0 + i * getWidth(), 0, (i + 1) * getWidth(),                    getHeight());        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        mDetector.onTouchEvent(event);// 委托手势识别器处理        switch (event.getAction()) {        case MotionEvent.ACTION_UP:            // 1.获取当前滑动的位置            // 2.根据当前位置,确定应该跳到第几个页面            // 3.跳到确定页面            int scrollX = getScrollX();            // System.out.println("scrollX:" + scrollX);            // 计算应该跳转到下一个页面的哪个位置            int pos = (scrollX + getWidth() / 2) / getWidth();            // //350 / 320 = 1            // int pos = scrollX / getWidth();            // // 350% 320 = 30            // int offset = scrollX % getWidth();            // if (offset > getWidth() / 2) {            // pos++;            // }            // System.out.println("pos:" + pos);            // 防止pos过大            if (pos > getChildCount() - 1) {                pos = getChildCount() - 1;            }            // 移动到确定页面            // scrollTo(pos * getWidth(), 0);            setCurrentItem(pos);            break;        default:            break;        }        return true;    }    // 当调用startScroll后,系统会不断回调此方法    @Override    public void computeScroll() {        if (mScroller.computeScrollOffset()) {// 判断滑动回调有没有结束            int currX = mScroller.getCurrX();// 获取当前应该移动到的位置            System.out.println("currX:" + currX);            scrollTo(currX, 0);// 移动到确定位置            invalidate();// 刷新界面        }    }    private OnPageChangeListener mListener;    public void setOnPageChangeListener(OnPageChangeListener listener) {        mListener = listener;    }    public interface OnPageChangeListener {        public void onPageSelected(int position);    }    /**     * 切换到某个具体的页面     *      * @param position     */    public void setCurrentItem(int pos) {        // 平滑的移动到某个位置        int distance = pos * getWidth() - getScrollX();// 目标位置减去当前位置,获得要滑动的距离        // 开始滑动, 滑动时间等于距离绝对值,        // 保证距离越长,时间越久(此方法不会产生滑动,而是会导致不断回调computeScroll,需要在这个方法中处理滑动逻辑)        mScroller.startScroll(getScrollX(), 0, distance, 0, Math.abs(distance));// 参1:开始x,                                                                                // 参2:开始y;参3:x偏移,参4:y偏移;参5:滑动时间        invalidate();// 刷新界面,保证滑动器正常运行        // 页面切换的回调        if (mListener != null) {            mListener.onPageSelected(pos);        }    }    int startX;    int startY;    // 事件中断 onInterceptTouchEvent->onTouchEvent    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        // 如果左右滑动, 就需要拦截, 上下滑动,不需要拦截        switch (ev.getAction()) {        case MotionEvent.ACTION_DOWN:            mDetector.onTouchEvent(ev);// 将ACTION_DOWN传递给手势识别器, 避免事件丢失            startX = (int) ev.getX();            startY = (int) ev.getY();            break;        case MotionEvent.ACTION_MOVE:            int endX = (int) ev.getX();            int endY = (int) ev.getY();            int dx = endX - startX;            int dy = endY - startY;            if (Math.abs(dx) > Math.abs(dy)) {                // 左右滑动                return true;// 中断事件传递, 不允许孩子响应事件了, 由父控件处理            }            break;        default:            break;        }        return false;// 不拦截事件,优先传递给孩子处理    }    // 事件分发dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        return super.dispatchTouchEvent(ev);    }}
0 0
原创粉丝点击