自定義Viewpager

package com.viewpager;


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;
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章