觉得博文有用,请点赞,请评论,请关注,谢谢!~
项目源码下载: http://download.csdn.net/detail/iwanghang/9721146
老规矩,先上GIF动态图,看个效果,如果符合你的项目或者确定你要了解的内容,再往下看吧:
跟前一篇博文相比:
1、添加了RadioButton。
2、实现了RadioButton的选中时,设置ViewPager下标。
3、实现了滑动页面ViewPager下标改变时,RadioButton的选中状态改变。
4、实现了添加页面后,将页面的孩子控件显示出来。
5、遗留一个问题,看GIF动态图可以发现,我们后面解决。
※博文结尾有解决的GIF动图和对应代码。
MainActivity.java:
package com.iwanghang.mygesturedetector; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.RadioButton; import android.widget.RadioGroup; public class MainActivity extends AppCompatActivity { private MyViewPager myViewPager; private RadioGroup rg_main; private int[] ids = {R.drawable.a,R.drawable.b,R.drawable.c, R.drawable.d,R.drawable.e,R.drawable.f}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getSupportActionBar().hide(); myViewPager = (MyViewPager) findViewById(R.id.myViewPager); rg_main = (RadioGroup) findViewById(R.id.rg_main); // 添加页面 for (int i = 0; i <ids.length ; i++) { ImageView iv = new ImageView(this); iv.setBackgroundResource(ids[i]); //iv.setImageResource(ids[i]); myViewPager.addView(iv); } // 添加测试页面 View testView = View.inflate(this,R.layout.test,null); myViewPager.addView(testView); // 添加RadioButton for (int i = 0; i < myViewPager.getChildCount(); i++) { RadioButton button = new RadioButton(this); // 实例化RadioButton button.setId(i); // 给每个RadioButton设置一个id if(i==0){ // 设置第一个id选中状态 button.setChecked(true); } rg_main.addView(button); // 添加到RadioGroup集合中 } // 设置RadioGroup选中状态的变化 -> 这里是根据RadioButton设置ViewPager // 还需要根据ViewPager的滑动 设置 RadioButton的选中状态 rg_main.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { myViewPager.scrollToPager(checkedId); // 根据下标位置定位到具体的某个页面 } }); // 设置监听页面的改变 MyOnPagerChangeListener mOnPagerChangeListener = new MyOnPagerChangeListener(); myViewPager.setOnPagerChangeListener(mOnPagerChangeListener); } class MyOnPagerChangeListener implements MyViewPager.OnPagerChangeListener { @Override public void onScrollToPager(int position) { rg_main.check(position); // RadioGroup的check方法,设置选中状态 } } // // 监听页面的改变 // public interface OnPagerChangeListener{ // // 当页面改变的时候回调这个方法 // void onScrollToPager(int position); // 回传页面下标 // } // private OnPagerChangeListener mOnPagerChangeListener; // public void setOnPagerChangeListener(OnPagerChangeListener listener){ // mOnPagerChangeListener = listener; // } }MyViewPager.java:
package com.iwanghang.mygesturedetector; 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 */ public class MyViewPager extends ViewGroup{ /** * 手势识别 * 1、定义出来 * 2、实例化 -> 把想要的方法给重写 * 3、在OnTouchEvent()把时间传递给手势识别器 */ private GestureDetector detector; // 1、定义出来 /** * 当前页面的下标位置 */ private int currentIndex; //private MyScroller myScroller; // 自己写的回弹效果 private Scroller myScroller; // 原生的回弹效果 public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); initView(context); // 2、实例化 } private void initView(final Context context) { //myScroller = new MyScroller(); // 自己写的回弹效果 myScroller = new Scroller(context); // 原生的回弹效果 // 2、实例化 detector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { //scrollBy((int)distanceX, (int)distanceY); // 这里为了演示,可以上下左右滑动 scrollBy((int)distanceX, getScrollY()); // Y轴保持在创建时的起始值,我们一般这么用 //Toast.makeText(context, ""+e1+"|"+e2+"|"+distanceX+"|"+distanceY, Toast.LENGTH_SHORT).show(); return true; } }); } @Override protected void onLayout(boolean b, int i, int i1, int i2, int i3) { // 遍历孩子,给每个孩子指定在屏幕的坐标位置 for (int n = 0; n <getChildCount() ; n++) { View childView = getChildAt(n); childView.layout(n*getWidth(),0,(n+1)*getWidth(),getHeight()); } } private float startX; @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); // 把时间传递给手势识别器 detector.onTouchEvent(event); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: // 记录坐标 startX = event.getX(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: // 新的坐标 float endX = event.getX(); // 下标位置 int tempIndex = currentIndex; // 计算偏移量 if ((startX-endX)>getWidth()/2){ // 显示下一个页面 tempIndex++; }else if ((endX-startX)>getWidth()/2){ // 显示上一个页面 tempIndex--; } scrollToPager(tempIndex); break; } return true; } /** * pager计算 */ public void scrollToPager(int tempIndex){ if (tempIndex < 0){ tempIndex = 0; } if (tempIndex > getChildCount()-1){ tempIndex = getChildCount()-1; } // 当前页面的下标位置 currentIndex = tempIndex; // 回传前判断 if(mOnPagerChangeListener != null){ mOnPagerChangeListener.onScrollToPager(currentIndex); } int distanceX = currentIndex*getWidth() - getScrollX(); //scrollTo(currentIndex*getWidth(), getScrollY()); //myScroller.startScroll(getScrollX(),getScrollY(),distanceX,0); myScroller.startScroll(getScrollX(),getScrollY(),distanceX,0,Math.abs(distanceX)); invalidate();// 强制绘制,导致下面computeScroll执行 } @Override public void computeScroll() { //super.computeScroll(); if(myScroller.computeScrollOffset()){ //得到移动这个一小段对应的坐标 float currX = myScroller.getCurrX(); scrollTo((int) currX,0); invalidate(); } } // 回传页面下标 public interface OnPagerChangeListener { void onScrollToPager(int position); } private OnPagerChangeListener mOnPagerChangeListener; /** * 设置页面改变的监听 */ public void setOnPagerChangeListener(OnPagerChangeListener listener) { mOnPagerChangeListener = listener; } // 显示页面的孩子 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec,heightMeasureSpec); } } }MyScroller.java:(这个不看也可以)
package com.iwanghang.mygesturedetector; import android.os.SystemClock; /** * 自己写的回弹效果 */ public class MyScroller { /** * X轴的起始坐标 */ private float startY; /** * Y轴的起始坐标 */ private float startX; /** * 在X轴要移动的距离 */ private int distanceX; /** * 在Y轴要移动的距离 */ private int distanceY; /** 开始的时间 */ private long startTime; /** * 总时间 */ private long totalTime = 500; /** * 是否移动完成 * false没有移动完成 * true:移动结束 */ private boolean isFinish; private float currX; /** * 得到坐标 */ public float getCurrX() { return currX; } public void startScroll(float startX, float startY, int distanceX, int distanceY) { this.startY = startY; this.startX = startX; this.distanceX = distanceX; this.distanceY = distanceY; this.startTime = SystemClock.uptimeMillis();//系统开机时间 this.isFinish = false; } /** * 速度 求移动一小段的距离 求移动一小段对应的坐标 求移动一小段对应的时间 true:正在移动 false:移动结束 * @return */ public boolean computeScrollOffset(){ if(isFinish){ return false; } //这一小段的结束时间 long endTime = SystemClock.uptimeMillis(); //这一小段所花的时间 long passTime = endTime - startTime; if(passTime < totalTime){ // 还没有移动结束 // 计算平均速度 //float voleCity = distanceX/totalTime; // 移动这个一小段对应的距离 float distanceSamllX = passTime* distanceX/totalTime; // 移动这一小段后对应x轴上的坐标 currX = startX + distanceSamllX; }else{ // 移动结束 isFinish = true; currX = startX + distanceX; } return true; } }activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" tools:context="com.iwanghang.mygesturedetector.MainActivity"> <RadioGroup android:id="@+id/rg_main" android:gravity="center_horizontal" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"/> <com.iwanghang.mygesturedetector.MyViewPager android:layout_below="@id/rg_main" android:id="@+id/myViewPager" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>test.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:textSize="20sp" android:text="这里只是一个TextVew 只有MyViewPager重写onMeasure把每个孩子都画出来的时候,这些文字才显示 这里可以左右滑动" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal"> <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="这里是ScrollView包裹LinearLayout包裹的TextView" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="这里不可以左右滑动" android:textAppearance="?android:attr/textAppearanceLarge" /> </LinearLayout> </ScrollView> </LinearLayout>
--------------------我是分割线--------------------
--------------------第一次改进--------------------
在MyViewPager加入onInterceptTouchEvent直接拦截事件分发:
// 在ViewGroup中,孩子的事件分发,返回true,拦截事件分发,会触发onTouchEvent() // 在ViewGroup中,孩子的事件分发,返回false,不拦截事件分发,事件继续传递 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true; }
--------------------我是分割线--------------------
--------------------第二次改进--------------------
继续改进onInterceptTouchEvent:
//private float startX; private float endX; private float endY; private float downX; private float downY; // 在ViewGroup中,孩子的事件分发,返回true,拦截事件分发,会触发onTouchEvent() // 在ViewGroup中,孩子的事件分发,返回false,不拦截事件分发,事件继续传递 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // 把事件传递给手势识别器 detector.onTouchEvent(ev); boolean result = false; // 定义一个布尔值,让事件默认情况下继续传递 switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: // 1、记录坐标 downX = ev.getX(); downY = ev.getY(); break; case MotionEvent.ACTION_MOVE: // 2、记录结束值 endX = ev.getX(); endY = ev.getY(); // 3、计算绝对值 distance距离 float distanceX = Math.abs(endX -downX); float distanceY = Math.abs(endY -downY); if (distanceX>distanceY && distanceX>10){ result = true; } break; } return result; }
项目源码下载: http://download.csdn.net/detail/iwanghang/9721146
转载请注明出处: http://blog.csdn.net/iwanghang/article/details/53839229
欢迎移动开发爱好者交流
沈阳或周边城市公司有意开发Android,请与我联系
联系方式
微信:iwanghang
QQ:413711276
邮箱:iwanghang@qq.com
沈阳或周边城市公司有意开发Android,请与我联系
联系方式
微信:iwanghang
QQ:413711276
邮箱:iwanghang@qq.com
项目源码下载: http://download.csdn.net/detail/iwanghang/9721146
觉得博文有用,请点赞,请评论,请关注,谢谢!~