转载请注明出处:
http://blog.csdn.net/iwanghang/article/details/53839229
觉得博文有用,请点赞,请评论,请关注,谢谢!~
项目源码下载: http://download.csdn.net/detail/iwanghang/9721146
老规矩,先上GIF动态图,看个效果,如果符合你的项目或者确定你要了解的内容,再往下看吧:
跟前一篇博文相比:
1、添加了RadioButton。
2、实现了RadioButton的选中时,设置ViewPager下标。
3、实现了滑动页面ViewPager下标改变时,RadioButton的选中状态改变。
4、实现了添加页面后,将页面的孩子控件显示出来。
5、遗留一个问题,看GIF动态图可以发现,我们后面解决。
※博文结尾有解决的GIF动图和对应代码。
MainActivity.java:
--------------------我是分割线--------------------
--------------------第一次改进--------------------
在MyViewPager加入onInterceptTouchEvent直接拦截事件分发:
--------------------我是分割线--------------------
--------------------第二次改进--------------------
继续改进onInterceptTouchEvent:
项目源码下载: http://download.csdn.net/detail/iwanghang/9721146
转载请注明出处: http://blog.csdn.net/iwanghang/article/details/53839229
项目源码下载: http://download.csdn.net/detail/iwanghang/9721146
觉得博文有用,请点赞,请评论,请关注,谢谢!~
觉得博文有用,请点赞,请评论,请关注,谢谢!~
项目源码下载: 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
觉得博文有用,请点赞,请评论,请关注,谢谢!~