效果图:

 

布局去指定自定义ViewPager:

view.custom.shangguigucustomview.MyCustomViewPager
<!-- 仿viewpager -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ShangGuiguTestActivity">

    <RadioGroup
        android:id="@+id/radio_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal"></RadioGroup>

    <view.custom.shangguigucustomview.MyCustomViewPager
        android:id="@+id/mycustom_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </view.custom.shangguigucustomview.MyCustomViewPager>

</LinearLayout>

 

自定义ViewPager:

public class MyCustomViewPager extends ViewGroup {

    private static final String TAG =  MyCustomViewPager.class.getSimpleName();

    /**
     * 定义手势识别器(注意:手势识别器没有事件拦截的特点)
     */
    private GestureDetector gestureDetector;

    private Scroller mScroller;

    public MyCustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);

        initView(context, attrs);
    }

    void initView(final Context context, AttributeSet attributeSet) {

        mScroller = new Scroller(context);

        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
            @Override
            public void onLongPress(MotionEvent e) {
                super.onLongPress(e);
                Toast.makeText(context, "你长按了", Toast.LENGTH_SHORT).show();
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Toast.makeText(context,"你双击了", Toast.LENGTH_SHORT).show();
                return super.onDoubleTap(e);
            }

            /**
             *
             * @param e1 开始按下的玩意
             * @param e2 up后的玩意
             * @param distanceX 滑动的X轴
             * @param distanceY 滑动的Y轴
             * @return
             */
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                // 自己不变,让自己内部的内容发生移动
                // scrollBy((int)distanceX, (int)distanceY); // 根据当前的位置进行移动

                scrollBy((int)distanceX, 0);  // getScaleY(); // 创建的时候默认的一个起始值
                // scrollTo((int)distanceX, 0 ); // 相对的是坐标,By相对的是距离

                return true; // 手势滑动 自己来处理,自己来消耗,所以retrun true;
            }
        });
    }

    /**
     * 1.为什么在一级画面能够显示,而在一级画面里面到子画面无法显示?
     *   就是因为一级画面在onLayout一级画面指定好位置了,系统就可以绘制好,而在画面中没有测量好,所以需要遍历子画面进行测量
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     *
     * 在ViewGroup中没有测量自己,只有测量孩子
     * ViewGroup (调用去测量孩子) --> View(测量自己)
     */
    /**
     *
     * @param widthMeasureSpec  1073742904 这个参数是父层视图给当前视图的宽度 和 模式
     * @param heightMeasureSpec 1073743468 这个参数是父层视图给当前视图的高度 和 模式
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        Log.i(TAG, "widthMeasureSpec:" + widthMeasureSpec + " heightMeasureSpec:" + heightMeasureSpec);

        // 得到宽高的Size
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

        // 得到高宽的模式
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        Log.i(TAG, ">>>>>>>> 🐶 sizeWidth:" + sizeWidth + " sizeHeight:" + sizeHeight);
        Log.i(TAG, ">>>>>>>> 🐶 modeWidth:" + modeWidth + " modeHeight:" + modeHeight);


        MeasureSpec.getMode(widthMeasureSpec);

        // 三种模式
        int unspecified = MeasureSpec.UNSPECIFIED; // 父容器不做任何限制,想多大就多大,属于:包裹
        int exactly = MeasureSpec.EXACTLY; // 父容器已检测出View所需大小
        int  atMost = MeasureSpec.AT_MOST; // 父容器已经规定了大小,不能超过规定的大小


        /**
         * 视图中又有视图,给自己的孩子东东
         */
        int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight);
        int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth);

        ///////// 与以下代码是分开的


        // 得到所以到孩子,给孩子测量,才能让系统到onDraw绘制出来
        int childCount = getChildCount();
        for (int i=0;i<childCount;i++) {
            View childAtView = getChildAt(i);
            childAtView.measure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    /**
     * 继承ViewGroup必须重写的方法
     * (不管是系统绘制还是自己来绘制,都是依赖于测量,或者是 onLayout来指定好来位置,才能绘制到显示)
     * @param booleanB 但布局变化但时候
     * @param l 左上角 距离 左边的宽度
     * @param t 左上角 距离 顶部的高度
     * @param r 右下角 距离 左边但宽度
     * @param b 右下角 距离 顶部但高度
     */
    @Override
    protected void onLayout(boolean booleanB, int l, int t, int r, int b) {

        // 我先得到一个孩子,设置位置,在展示看看
        /*View childView = getChildAt(0);
        childView.layout(0,0, (0 + 1) * getWidth(), getHeight());*/

        // 遍历所有的孩子
        for (int i=0; i<getChildCount(); i++){
            View childAtView = getChildAt(i);
            l = i*getWidth(); // 左上角距离左边的距离,第一个页面:0*任何都得0, 第二个页面:1*宽度的一个宽度,..
            t = 0; // 左上角 我要贴到顶部,所以不需要距离顶部
            r = getWidth() * (i+1); // 右下角 距离左边到宽度很重要,第一个页面需要设置屏幕宽度,第二个页面需要 2*屏幕宽度,...
            b = getHeight(); // 右下角 距离顶部到高度,一直是屏幕高度就好来
            /**
             * 指定每个孩子到位置
             */
            childAtView.layout(l, t, r, b); // 都已经人为都指定好了,所以测量都方法就不需要了
        }
    }

    /*@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }*/

    private float startX;
    private float endX;
    private int tempIndex;

    private IMyCustomViewPagerBack back;

    public void setIBack(IMyCustomViewPagerBack back) {
        this.back = back;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        gestureDetector.onTouchEvent(event); // 要把事件传递给(手势识别器)
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                if (getWidth()/2 < startX - endX) {
                    tempIndex ++;
                } else if (getWidth() / 2 < endX - startX ) {
                    tempIndex --;
                }

                // 防止越界
                if (tempIndex < 0) {
                    tempIndex = 0;
                } else if (tempIndex > getChildCount()-1) {
                    tempIndex = getChildCount() - 1;
                }

                toScroller(tempIndex);

                break;
            case MotionEvent.ACTION_MOVE:
                endX = event.getX();
                break;
            default:
                break;
        }
        return true;
    }

    public void toScroller(int tempIndex) {

        if (null != back) {
            back.backMethod(tempIndex);
        }

        // 总距离
        test = (tempIndex * getWidth()) - getScrollX();
        v = 0;

        // scrollTo(test, 0);

        // handler.sendEmptyMessage(0);

        invalidate();



        mScroller.startScroll(getScrollX(),getScrollY(), test, Math.abs(test));

    }

    private int test;
    private int v = 10;

    private android.os.Handler handler = new android.os.Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            switch (msg.what) {
                case 0:
                    scrollTo(v, getScrollY());
                    handler.sendEmptyMessageDelayed(1, 500);
                    break;
                case 1:
                    if (v < test) {
                       v = v + v;
                        scrollTo(v, getScrollY());
                        handler.sendEmptyMessageDelayed(1, 500);
                    }
                    break;
            }
        }
    };

    @Override
    public void computeScroll() {
        super.computeScroll();

        if (mScroller.computeScrollOffset()) {
            int curX =  mScroller.getCurrX();
            scrollTo(curX, 0);
            invalidate();
        }
    }

    float mystartX;
    float mystartY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        super.onInterceptTouchEvent(ev);
        // return true; // 拦截事件 将会触发onTouchEvent
        // return false; // 不拦截事件,将事件交给自控件

        // 把事件给收拾识别器
        gestureDetector.onTouchEvent(ev);

        boolean result = false; // 默认是不拦截的
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录触摸下的值
                mystartX = ev.getX();
                mystartY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                // 记录摸移动的值
                float endX = ev.getX();
                float endY = ev.getY();

                // 计算绝对值
                float jueduiX = Math.abs(endX - mystartX);
                float jueduiY = Math.abs(endY - mystartY);

                // 计算是否是横行滑动
                if (jueduiX > jueduiY && Math.abs(jueduiX) > 6) {
                    result = true;
                } else {
                    result = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        return result;
    }
}

 

在Activity如何去使用自定义ViewPager:

     /**
         * 仿viewpager
         */
        myCustomViewPager = (MyCustomViewPager) findViewById(R.id.mycustom_viewpager);

        radioGroup = (RadioGroup) findViewById(R.id.radio_group);

        // 先给View增加一个ImageView
        // ImageView imageView = new ImageView(this);
        // imageView.setBackgroundResource(R.mipmap.a1);
        // myCustomViewPager.addView(imageView);

        int[] imgs  = {R.mipmap.fang_view_pager1,R.mipmap.fang_view_pager2,R.mipmap.fang_view_pager3,
         R.mipmap.fang_view_pager4, R.mipmap.fang_view_pager5, R.mipmap.fang_view_pager6};
for (int i = 0; i < imgs.length; i++) { ImageView imageView = new ImageView(this); imageView.setBackgroundResource(imgs[i]); myCustomViewPager.addView(imageView); } // 把布局文件添加到自定义ViewPager中 View testLayout = View.inflate(this, R.layout.my_custom_viewpager_layout, null); myCustomViewPager.addView(testLayout, 2); for (int j=0; j<myCustomViewPager.getChildCount(); j++) { RadioButton radioButton = new RadioButton(this); radioButton.setId(j); if (j == 0) { radioButton.setChecked(true); } radioGroup.addView(radioButton); } myCustomViewPager.setIBack(new IMyCustomViewPagerBack() { @Override public void backMethod(int index) { // Toast.makeText(MainActivity.this, "index:" + index, Toast.LENGTH_SHORT).show(); radioGroup.getCheckedRadioButtonId(); radioGroup.check(index); } }); radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { myCustomViewPager.toScroller(i); } });