Android自定义View——教你制作ViewPager(二)

教你制作ViewPager(二)


本篇文章介绍:处理滑动监听,处理滑动冲突增加ViewPager的指示器

欢迎关注我的CSDN博客,Hensen_的博客,http://blog.csdn.net/qq_30379689


步骤一:在上篇中介绍了ViewPager的实现后,接下来介绍指示器的完成,指示器用RadioButton来实现,在xml中编写RadioGroup

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

    <com.handsome.app2.View.Custom.MyViewPager
        android:id="@+id/vp_my"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
步骤二:在主页面中对RadioButton初始化

final RadioGroup rg = (RadioGroup) findViewById(R.id.rg);
        for (int i = 0; i < 4; i++) {
            RadioButton rb = new RadioButton(this);
            //这里用使用0,1,2,3为id,对应ViewPager的pos值
            rb.setId(i);
            rg.addView(rb);
            //默认第一个选中
            if (i == 0) {
                rb.setChecked(true);
            }
        }
步骤三:回到我们的 MyViewPager 类,创建ViewPager的监听事件 接口
private OnPagerChangeListener listener;

    public interface OnPagerChangeListener {
        void onPagerChange(int pos);
    }

    public void setOnPagerChangeListener(OnPagerChangeListener listener) {
        this.listener = listener;
    }
步骤四:创建ViewPager设置页面的方法,并调用接口的 onPagerChange 方法

/**
     * 设置当前页面
     * @param pos
     */
    public void setCurrentItem(int pos) {
        mScroller.startScroll(getScrollX(), 0, pos * getWidth() - getScrollX(), 0, Math.abs(pos * getWidth()));
        invalidate();
        //页面切换接口回调
        if (listener != null) {
            listener.onPagerChange(pos);
        }
    }
这个时候,滑动事件处理就可以用 setCurrentItem 方法来替代

case MotionEvent.ACTION_UP:
                int scrollX = getScrollX();
                //你滑动的距离加上屏幕的一半,除以屏幕宽度,如果你滑动距离超过了屏幕的一半,这个pos就加1
                int pos = (scrollX + getWidth() / 2) / getWidth();
                //滑到最后一张的时候,不能出边界
                if (pos >= image_id.length) {
                    pos = image_id.length - 1;
                }
                //绝对滑动,直接滑到指定的x值
                //scrollTo(pos * getWidth(), 0);
                //自然滑动,从手滑到的地方开始,滑动距离是页面宽度减去滑到的距离,时间由路程的大小来决定
//                mScroller.startScroll(scrollX, 0, pos * getWidth() - scrollX, 0, Math.abs(pos * getWidth()));
//                invalidate();
                setCurrentItem(pos);
                break;
步骤五:回到Activity中进行绑定事件

final MyViewPager myViewPager = (MyViewPager) findViewById(R.id.vp_my);
        //按钮点击事件
        rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                int pos = checkedId;
                myViewPager.setCurrentItem(pos);
            }
        });
        //ViewPager切换事件
        myViewPager.setOnPagerChangeListener(new MyViewPager.OnPagerChangeListener() {
            @Override
            public void onPagerChange(int pos) {
                rg.check(pos);
            }
        });
这样就完成了切换效果,看效果图:



滑动冲突的处理:

步骤一:我们在ViewPager中嵌套一个ScrollView作为它的子View,这样ViewPager是左右滑动,ScrollView是上下滑动,那么就造成了滑动冲突

创建一个ScrollView的xml文件:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hensen_的博客"
            android:textSize="60dp" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="http://blog.csdn.net/qq_30379689" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hensen_的博客"
            android:textSize="60dp" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="http://blog.csdn.net/qq_30379689" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hensen_的博客"
            android:textSize="60dp" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="http://blog.csdn.net/qq_30379689" />
    </LinearLayout>
</ScrollView>
在主界面中 添加这个页面 到ViewPager中,同时增加一个RadioButton
// 添加ScrollView页面
        View testView = View.inflate(this, R.layout.view_scroller, null);
        myViewPager.addView(testView, 1);
这个时候你可以看到增加了一个页面,但是 页面是空白的:由于ViewGroup只遍历它的一个子View(即在这里的ScrollView),并不会去遍历ScrollView里面的内容,所以必须重写它的 onMeasure方法,对ScrollView的子View进行遍历
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        }
    }
查看效果图:

Android自定义View——教你制作ViewPager(二)_第1张图片
这个时候你会发现这个页面只能上下滑动不能左右滑动,所以需要处理滑动事件冲突

步骤二:重写父控件的onInterceptTouchEvent方法,如果是左右滑动,我们的父控件就把滑动事件拦截下来

int startX;
    int startY;
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 如果左右滑动, 就需要拦截, 上下滑动,不需要拦截
        switch (ev.getAction()) {
            case MotionEvent.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;// 不拦截事件,优先传递给孩子处理
    }
这个时候还需要把将 ACTION_DOWN传递给手势识别器,因为拦截了MOVE的事件后,DOWN的事件也要给拦截给手势识别器,否则会 丢失事件

 switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDetector.onTouchEvent(ev);// 将ACTION_DOWN传递给手势识别器, 避免事件丢失
                startX = (int) ev.getX();
                startY = (int) ev.getY();
                break;
到现在,ViewPager就完成了滑动冲突的处理,既能 上下滑动和左右滑动



结语:

经过学习自定义ViewPager一和二,其包含的知识点有:自定义ViewGroup,监听滑动接口的编写,手势识别器以及Scroller的使用,和滑动冲突的处理,如果对某个知识点不懂的,应该自行查阅资料进行学习,希望你们可以自定义出属于自己的View出来。



你可能感兴趣的:(viewpager,控件,自定义view)