import com.viewpager.MyViewPager.OnPageChangeListener;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
public class MainActivity extends Activity {
private MyViewPager myViewPager;
//图片id
private int[] imageIds = new int[]{R.drawable.a1,R.drawable.a2,R.drawable.a3, R.drawable.a4, R.drawable.a5, R.drawable.a6 };
private RadioGroup rgGroup;//复选按钮
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//自定义ViewPager
myViewPager = (MyViewPager) findViewById(R.id.my_viewpager);
final RadioGroup rgGroup = (RadioGroup) findViewById(R.id.rg_group);
//动态给viewpager添加imageView
for(int i=0;i<imageIds.length;i++){
ImageView view = new ImageView(this);
view.setBackgroundResource(imageIds[i]);
myViewPager.addView(view);
/**添加之后发现没有图片,
* 原因是需要测量高度和宽度,否则Viewpager不知道设置多大的空间给你
*
*/
}
/**插入之后发现问题,1.超过屏幕,必须要测量宽和高
*
* ACTION_DOWN被子控件(ScrollView)吃掉了, 导致viewpager的手势识别器丢失了这个事件
* 故判断执行onInterceptTouchEvent方法
*/
View testView = View.inflate(this, R.layout.list_item_test, null);
myViewPager.addView(testView, 2);// 在第三个位置插入一个测试页面布局
//动态添加RadioButton
for(int i=0;i<imageIds.length;i++){
RadioButton rb = new RadioButton(this);
rb.setId(i);// 以位置为id
rgGroup.addView(rb);
if(i==0){
rb.setChecked(true);// 第一个模式选中
}
}
// RadioButton被选中的事件监听
rgGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
int pos =checkedId;// 位置信息刚好等于id
myViewPager.setCurrentItem(pos);
}
});
myViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageChanged(int position) {
// TODO Auto-generated method stub
int id = position;// 位置信息刚好等于id
rgGroup.check(id);
}
});
}
}
package com.viewpager;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.Scroller;
public class MyViewPager extends ViewGroup {
private Scroller scroller;
private GestureDetector gestureDetector;
private int startX;
private int startY;
private OnPageChangeListener mListener;
public MyViewPager(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyViewPager(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
private void init() {
gestureDetector = new GestureDetector(getContext(),
new GestureDetector.SimpleOnGestureListener(){
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 参1:起点动作, 参2:终点动作;参3:x方向滑动距离;参4:y方向滑动距离
// 滑动页
scrollBy((int) distanceX, 0);// 页面滑动一定距离;x:水平方向的滑动偏移量;y:竖直方向滑动的偏移量;(相对偏移)
// scrollTo(x, y);//绝对位移;和当前位置无关,滑动到确定好的位置上
return super.onScroll(e1, e2, distanceX, distanceY);
}
});
//滑动器,实现平滑效果
scroller = new Scroller(getContext());
}
//设置布局宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 测量viewpager本身的宽高
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//遍历所有viewPager所有子控件,手动测试每个子控件的宽高(修复页面无法展示的bug)
for(int i=0;i<getChildCount();i++){
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
// 宽高模式
// MeasureSpec.AT_MOST; 至多, wrap_content
// MeasureSpec.EXACTLY 确定值, 宽高写死多少dp, match_parent
// MeasureSpec.UNSPECIFIED 未指定
/*int mode = MeasureSpec.getMode(widthMeasureSpec);// 获取宽高模式
int size = MeasureSpec.getSize(widthMeasureSpec);// 获取具体宽高值
*/
}
//设置布局位置
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
/**遍历viewPa所有子控件,手动安放每个子控件的位置
* 保证子控件能够正常展示
*
*/
//保证所有子控件一字排开
for(int i=0;i<getChildCount();i++){
getChildAt(i).layout(getWidth()*i, 0, getWidth()*(i+1), getHeight());
}
}
// dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent
// 事件分发的方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
// 事件中断的方法
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 判断当前的滑动方式,如果上下滑动,交由子控件处理;如果左右滑动,交由viewpager处理
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) ev.getX();
startY = (int) ev.getY();
// ACTION_DOWN被子控件(ScrollView)吃掉了, 导致viewpager的手势识别器丢失了这个事件
gestureDetector.onTouchEvent(ev);// 给手势识别器补上ACTION_DOWN的事件
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;// 返回true表示父控件要拦截此事件,不在给子控件传递
}
break;
default:
break;
}
return false;// 返回false表示父控件不拦截此事件,交给子控件处理
}
//设置触摸滑动事件
@Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);// 委托手势识别器来处理触摸事件
switch (event.getAction()) {
case MotionEvent.ACTION_UP://手指抬起后,要根据当前位置,来确定下一个页面
int scrollX = getScrollX();// 获取滑动后的位置
int pos = scrollX/getWidth();//获取当前位置
int offset =scrollX%getWidth();// 获取多出来的距离
if(offset>getWidth()/2){//如果多出来的距离大于viewpager宽度一半,就要跳到下一个页面
pos++;
}
if(pos>getChildCount()-1){
pos=getChildCount()-1;
}
System.out.println("当前位置:" + pos);
//设置完成后需要从新更新位置
setCurrentItem(pos);
break;
default:
break;
}
return true;
}
//开始滑动动画时会回调computeScroll,在此方法中更新页面
@Override
public void computeScroll() {
if(scroller.computeScrollOffset()){// 判断滑动是否已经结束,没有结束才处理以下逻辑
int currX = scroller.getCurrX();//获取当前的滑动位置
scrollTo(currX, 0);// 滑动到目标位置
invalidate();//刷新界面
System.out.println("currX:" + currX);
}
}
public void setCurrentItem(int pos) {
// 滑动到下个页面
// scrollTo(pos * getWidth(), 0);
// 开始滑动
int distance = pos*getWidth()-getScrollX();// 移动距离 = 目标位置- 当前位置
// 距离越长,时间越久,可以让时间=距离
// 此处并不会立即启动滑动动画,而是不断回调computeScroll这个方法
// 参1:起始x位置;参2:起始y位置;参3:x方向移动距离;参4:y方向移动距离;参5:移动时间
scroller.startScroll(getScrollX(), 0, distance, 0, Math.abs(distance));
invalidate();
// 回调页面位置信息
if (mListener != null) {
mListener.onPageChanged(pos);
}
}
/**
* 页面切换的回调接口
*/
public interface OnPageChangeListener{
public void onPageChanged(int position);
}
public void setOnPageChangeListener(OnPageChangeListener listener) {
mListener = listener;
}
}