zoukankan      html  css  js  c++  java
  • 自定义ViewPager+RadioGroup联动效果的实现

    package com.loaderman.myviewpager;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.RadioButton;
    import android.widget.RadioGroup;
    public class MainActivity extends AppCompatActivity {
        private MyViewPager mViewPager;
        private RadioGroup rgGroup;
        private int[] mImageIds = new int[]{R.drawable.a1, R.drawable.a2, R.drawable.a3, R.drawable
                .a4, R.drawable.a5, R.drawable.a6};
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mViewPager = (MyViewPager) findViewById(R.id.viewpager);
            rgGroup = (RadioGroup) findViewById(R.id.rg_group);
            //给自定义Viewpager添加图片
            for (int id : mImageIds) {
                ImageView view = new ImageView(this);
                view.setBackgroundResource(id);
                mViewPager.addView(view);
            }
            //添加测试页面布局
            View view = View.inflate(this, R.layout.item_test, null);
            mViewPager.addView(view, 2);
            //动态添加RaidoButton
            for (int i = 0; i <= mImageIds.length; i++) {
                RadioButton rb = new RadioButton(this);
                rb.setId(i);//以当前位置为id
                rgGroup.addView(rb);
                if (i == 0) {
                    rb.setChecked(true);
                }
            }
            //点击RadioButton, 切换页面
            rgGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(RadioGroup group, int checkedId) {
                    System.out.println("checkedId:" + checkedId);
                    int pos = checkedId;
                    mViewPager.setCurrentItem(pos);
                }
            });
            //切换页面, 更新RadioButton
            mViewPager.addOnPageChangeListener(new MyViewPager.OnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    int id = position;
                    rgGroup.check(id);
                }
            });
    
        }
    }
    
    package com.loaderman.myviewpager;
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Scroller;
    /**
     * 自定义ViewPager流程:
     * 1. 写一个类继承ViewGroup
     * 2. 在actvity中添加图片对象
     * 3. 重写onLayout, 保证子控件一字排开
     * 4. 滑动布局,切换页面, 手势识别器 onScroll: scrollBy, scrollTo
     * 5. 平滑滑动效果 Scroller滑动器
     * 6. 加测试页面ScrollView
     * 7. 重写onMeasure测量所有子控件
     * 8. 事件传递流程, 苹果例子
     * 9. 事件拦截流程
     * 10. 保证viewpager和scrollview分别处理相关事件
     * 11. 添加RadioButton
     * 12. 点击RadioButton切换页面
     * 13. 滑动页面, 切换RadioButton
     */
    public class MyViewPager extends ViewGroup {
        private GestureDetector mDetector;
        private Scroller        mScroller;
        private int             startX;
        private int             startY;
        public MyViewPager(Context context) {
            this(context, null);
        }
        public MyViewPager(Context context, AttributeSet attrs) {
            this(context, attrs, -1);
        }
        public MyViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
        private void init() {
            mDetector = new GestureDetector(getContext(), new GestureDetector
                    .SimpleOnGestureListener() {
                //触摸滑动的方法
                @Override
                public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float
                        distanceY) {
                    //distanceX: 水平滑动距离
                    scrollBy((int) distanceX, 0);//基于当前位置进行滑动, 参1:水平滑动的偏移量, 相对位置
                    return super.onScroll(e1, e2, distanceX, distanceY);
                }
            });
            //滑动器
            mScroller = new Scroller(getContext());
        }
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);//设置ViewPager本身的尺寸
            //遍历所有子控件,设置每个控件的尺寸
            //解决测试页面显示白板的问题
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                child.measure(widthMeasureSpec, heightMeasureSpec);
            }
            //widthMeasureSpec: 并不是真实的宽高信息, 它包含两部分, 1: 宽高模式信息; 2. 具体的尺寸
            // System.out.println("widthMeasureSpec:" + widthMeasureSpec);
            // System.out.println("heightMeasureSpec:" + heightMeasureSpec);
            //MeasureSpec.AT_MOST; 至多模式, 当前控件有多大就显示多大 wrap_content
            //MeasureSpec.EXACTLY; 确定模式, 宽高写死dp, match_parent(父控件多大,我就多大,所以也是确定的)
            //MeasureSpec.UNSPECIFIED; 未确定模式, ListView, ScrollView
    
            //        int mode = MeasureSpec.getMode(widthMeasureSpec);
            //        int size = MeasureSpec.getSize(widthMeasureSpec);
            //
            //        System.out.println("mode:" + mode);
            //        System.out.println("size:" + size);
        }
        //设置控件的位置
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            //遍历所有子控件, 设置每个子控件位置
            //子控件一字排开
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                child.layout(getWidth() * i, 0, getWidth() * (i + 1), getHeight());
            }
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            mDetector.onTouchEvent(event);
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    System.out.println("ViewPager 按下...");
                    break;
                case MotionEvent.ACTION_MOVE:
                    System.out.println("ViewPager 移动...");
                    break;
                case MotionEvent.ACTION_UP:
                    System.out.println("ViewPager 抬起...");
                    //手指抬起
                    //确定下一页的位置
                    int scrollX = getScrollX();//获取当前移动后的x值
                    // System.out.println("scrollX:" + scrollX);
                    //计算当前页面位置
                    int currPos = scrollX / getWidth();
                    // System.out.println("currPos:" + currPos);
                    int offset = scrollX % getWidth();//多划出的距离
                    if (offset > getWidth() / 2) {
                        currPos++;
                    }
                    //避免越界 0->图片个数-1
                    if (currPos < 0) {
                        currPos = 0;
                    }
                    if (currPos > getChildCount() - 1) {
                        currPos = getChildCount() - 1;
                    
                    //System.out.println("下一页位置:" + currPos);
    
                    //跳到下一页位置
                    // scrollTo(currPos * getWidth(), 0);//绝对位置,移动到确定位置
                    //计算滑动距离
                    //                int dx = currPos * getWidth() - getScrollX();//目标位置-当前位置=滑动距离
                    //                //此方法不能产生滑动的动画效果, 会导致回调computeScroll方法, 需要在computeScroll方法中处理动画
                    //                mScroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(dx));//距离和时间要成正比
                    //                invalidate();//要刷新界面
                    setCurrentItem(currPos);
                    break;
                default:
                    break;
            }
            return true;
        }
        //此方法会回调多次, 每一次回调后修改页面位置, 连续在一起就形成动画
        @Override
        public void computeScroll() {
            super.computeScroll();
            if (mScroller.computeScrollOffset()) {//判断有没有滑动结束
                int currX = mScroller.getCurrX();//获取当前应该滑动到的位置
                System.out.println("currX:" + currX);
                scrollTo(currX, 0);//滑动到特定位置
                invalidate();//要刷新界面
            }
        }
        //事件分发
        //dispatchTouchEvent->onInterceptTouchEvent-->onTouchEvent
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            return super.dispatchTouchEvent(ev);
        }
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            //如果上下滑动, 不需要中断事件
            //左右滑动, 才需要中断事件
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    startX = (int) ev.getX();
                    startY = (int) ev.getY();
                    //由于按下之后, 返回false, 按下事件被子控件处理,导致ViewPager丢掉了按下事件,滑动时页面出现bug
                    //补上按下事件
                    mDetector.onTouchEvent(ev);
                    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;//表示中断事件传递, 交给当前ViewPager处理, 子控件无法处理
                    }
                    break;
                default:
                    break;
            }
            return false;//不中断事件, 交给子控件(ScrollView)处理
        }
        //设置当前页面
        public void setCurrentItem(int pos) {
            //计算滑动距离
            int dx = pos * getWidth() - getScrollX();//目标位置-当前位置=滑动距离
            //此方法不能产生滑动的动画效果, 会导致回调computeScroll方法, 需要在computeScroll方法中处理动画
            mScroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(dx));//距离和时间要成正比
            invalidate();//要刷新界面
            //回调页面位置
            if (listener != null) {
                listener.onPageSelected(pos);
            }
        }
        private OnPageChangeListener listener;
        public void addOnPageChangeListener(OnPageChangeListener listener) {
            this.listener = listener;
        }
        public interface OnPageChangeListener {
            public void onPageSelected(int position);
        }
    }
    

     activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.loaderman.myviewpager.MainActivity">
    
        <RadioGroup
            android:id="@+id/rg_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
        </RadioGroup>
    
        <com.loaderman.myviewpager.MyViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
    </LinearLayout>
    

     item_test.xml

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <!--item_test-->
        <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="测试文本"
                android:textSize="30sp"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试文本"
                android:textSize="30sp"/>
        </LinearLayout>
    </ScrollView>
    

     效果:

  • 相关阅读:
    Nginx的配置文件详解(超详细)
    淘宝地址爬取及UI展示
    点击观看
    winform picturebox设置布局样式
    vs的一个不经常用的快捷键
    C# 开发windows服务
    winform窗体置顶
    C# mysql set和enum属性字段的读取和添加
    winform窗体绑定监控键盘事件
    html5创建的sqlite存放为止以及在手机中的位置
  • 原文地址:https://www.cnblogs.com/loaderman/p/6514608.html
Copyright © 2011-2022 走看看