效果圖:android
佈局去指定自定義ViewPager:canvas
view.custom.shangguigucustomview.MyCustomViewPager
<!-- 仿viewpager --> <LinearLayout 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" android:orientation="vertical" tools:context=".ShangGuiguTestActivity"> <RadioGroup android:id="@+id/radio_group" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal"></RadioGroup> <view.custom.shangguigucustomview.MyCustomViewPager android:id="@+id/mycustom_viewpager" android:layout_width="match_parent" android:layout_height="match_parent"> </view.custom.shangguigucustomview.MyCustomViewPager> </LinearLayout>
自定義ViewPager:ide
public class MyCustomViewPager extends ViewGroup { private static final String TAG = MyCustomViewPager.class.getSimpleName(); /** * 定義手勢識別器(注意:手勢識別器沒有事件攔截的特色) */ private GestureDetector gestureDetector; private Scroller mScroller; public MyCustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); initView(context, attrs); } void initView(final Context context, AttributeSet attributeSet) { mScroller = new Scroller(context); gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){ @Override public void onLongPress(MotionEvent e) { super.onLongPress(e); Toast.makeText(context, "你長按了", Toast.LENGTH_SHORT).show(); } @Override public boolean onDoubleTap(MotionEvent e) { Toast.makeText(context,"你雙擊了", Toast.LENGTH_SHORT).show(); return super.onDoubleTap(e); } /** * * @param e1 開始按下的玩意 * @param e2 up後的玩意 * @param distanceX 滑動的X軸 * @param distanceY 滑動的Y軸 * @return */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // 本身不變,讓本身內部的內容發生移動 // scrollBy((int)distanceX, (int)distanceY); // 根據當前的位置進行移動 scrollBy((int)distanceX, 0); // getScaleY(); // 建立的時候默認的一個起始值 // scrollTo((int)distanceX, 0 ); // 相對的是座標,By相對的是距離 return true; // 手勢滑動 本身來處理,本身來消耗,因此retrun true; } }); } /** * 1.爲何在一級畫面可以顯示,而在一級畫面裏面到子畫面沒法顯示? * 就是由於一級畫面在onLayout一級畫面指定好位置了,系統就能夠繪製好,而在畫面中沒有測量好,因此須要遍歷子畫面進行測量 * @param widthMeasureSpec * @param heightMeasureSpec * * 在ViewGroup中沒有測量本身,只有測量孩子 * ViewGroup (調用去測量孩子) --> View(測量本身) */ /** * * @param widthMeasureSpec 1073742904 這個參數是父層視圖給當前視圖的寬度 和 模式 * @param heightMeasureSpec 1073743468 這個參數是父層視圖給當前視圖的高度 和 模式 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.i(TAG, "widthMeasureSpec:" + widthMeasureSpec + " heightMeasureSpec:" + heightMeasureSpec); // 獲得寬高的Size int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); // 獲得高寬的模式 int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); Log.i(TAG, ">>>>>>>> 🐶 sizeWidth:" + sizeWidth + " sizeHeight:" + sizeHeight); Log.i(TAG, ">>>>>>>> 🐶 modeWidth:" + modeWidth + " modeHeight:" + modeHeight); MeasureSpec.getMode(widthMeasureSpec); // 三種模式 int unspecified = MeasureSpec.UNSPECIFIED; // 父容器不作任何限制,想多大就多大,屬於:包裹 int exactly = MeasureSpec.EXACTLY; // 父容器已檢測出View所需大小 int atMost = MeasureSpec.AT_MOST; // 父容器已經規定了大小,不能超過規定的大小 /** * 視圖中又有視圖,給本身的孩子東東 */ int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight); int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth); ///////// 與如下代碼是分開的 // 獲得因此到孩子,給孩子測量,才能讓系統到onDraw繪製出來 int childCount = getChildCount(); for (int i=0;i<childCount;i++) { View childAtView = getChildAt(i); childAtView.measure(widthMeasureSpec, heightMeasureSpec); } } /** * 繼承ViewGroup必須重寫的方法 * (無論是系統繪製仍是本身來繪製,都是依賴於測量,或者是 onLayout來指定好來位置,才能繪製到顯示) * @param booleanB 但佈局變化但時候 * @param l 左上角 距離 左邊的寬度 * @param t 左上角 距離 頂部的高度 * @param r 右下角 距離 左邊但寬度 * @param b 右下角 距離 頂部但高度 */ @Override protected void onLayout(boolean booleanB, int l, int t, int r, int b) { // 我先獲得一個孩子,設置位置,在展現看看 /*View childView = getChildAt(0); childView.layout(0,0, (0 + 1) * getWidth(), getHeight());*/ // 遍歷全部的孩子 for (int i=0; i<getChildCount(); i++){ View childAtView = getChildAt(i); l = i*getWidth(); // 左上角距離左邊的距離,第一個頁面:0*任何都得0, 第二個頁面:1*寬度的一個寬度,.. t = 0; // 左上角 我要貼到頂部,因此不須要距離頂部 r = getWidth() * (i+1); // 右下角 距離左邊到寬度很重要,第一個頁面須要設置屏幕寬度,第二個頁面須要 2*屏幕寬度,... b = getHeight(); // 右下角 距離頂部到高度,一直是屏幕高度就好來 /** * 指定每一個孩子到位置 */ childAtView.layout(l, t, r, b); // 都已經人爲都指定好了,因此測量都方法就不須要了 } } /*@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); }*/ private float startX; private float endX; private int tempIndex; private IMyCustomViewPagerBack back; public void setIBack(IMyCustomViewPagerBack back) { this.back = back; } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); gestureDetector.onTouchEvent(event); // 要把事件傳遞給(手勢識別器) switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = event.getX(); break; case MotionEvent.ACTION_UP: if (getWidth()/2 < startX - endX) { tempIndex ++; } else if (getWidth() / 2 < endX - startX ) { tempIndex --; } // 防止越界 if (tempIndex < 0) { tempIndex = 0; } else if (tempIndex > getChildCount()-1) { tempIndex = getChildCount() - 1; } toScroller(tempIndex); break; case MotionEvent.ACTION_MOVE: endX = event.getX(); break; default: break; } return true; } public void toScroller(int tempIndex) { if (null != back) { back.backMethod(tempIndex); } // 總距離 test = (tempIndex * getWidth()) - getScrollX(); v = 0; // scrollTo(test, 0); // handler.sendEmptyMessage(0); invalidate(); mScroller.startScroll(getScrollX(),getScrollY(), test, Math.abs(test)); } private int test; private int v = 10; private android.os.Handler handler = new android.os.Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: scrollTo(v, getScrollY()); handler.sendEmptyMessageDelayed(1, 500); break; case 1: if (v < test) { v = v + v; scrollTo(v, getScrollY()); handler.sendEmptyMessageDelayed(1, 500); } break; } } }; @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { int curX = mScroller.getCurrX(); scrollTo(curX, 0); invalidate(); } } float mystartX; float mystartY; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { super.onInterceptTouchEvent(ev); // return true; // 攔截事件 將會觸發onTouchEvent // return false; // 不攔截事件,將事件交給自控件 // 把事件給收拾識別器 gestureDetector.onTouchEvent(ev); boolean result = false; // 默認是不攔截的 switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // 記錄觸摸下的值 mystartX = ev.getX(); mystartY = ev.getY(); break; case MotionEvent.ACTION_MOVE: // 記錄摸移動的值 float endX = ev.getX(); float endY = ev.getY(); // 計算絕對值 float jueduiX = Math.abs(endX - mystartX); float jueduiY = Math.abs(endY - mystartY); // 計算是不是橫行滑動 if (jueduiX > jueduiY && Math.abs(jueduiX) > 6) { result = true; } else { result = false; } break; case MotionEvent.ACTION_UP: break; default: break; } return result; } }
在Activity如何去使用自定義ViewPager:佈局
/** * 仿viewpager */ myCustomViewPager = (MyCustomViewPager) findViewById(R.id.mycustom_viewpager); radioGroup = (RadioGroup) findViewById(R.id.radio_group); // 先給View增長一個ImageView // ImageView imageView = new ImageView(this); // imageView.setBackgroundResource(R.mipmap.a1); // myCustomViewPager.addView(imageView); int[] imgs = {R.mipmap.fang_view_pager1,R.mipmap.fang_view_pager2,R.mipmap.fang_view_pager3,
R.mipmap.fang_view_pager4, R.mipmap.fang_view_pager5, R.mipmap.fang_view_pager6}; for (int i = 0; i < imgs.length; i++) { ImageView imageView = new ImageView(this); imageView.setBackgroundResource(imgs[i]); myCustomViewPager.addView(imageView); } // 把佈局文件添加到自定義ViewPager中 View testLayout = View.inflate(this, R.layout.my_custom_viewpager_layout, null); myCustomViewPager.addView(testLayout, 2); for (int j=0; j<myCustomViewPager.getChildCount(); j++) { RadioButton radioButton = new RadioButton(this); radioButton.setId(j); if (j == 0) { radioButton.setChecked(true); } radioGroup.addView(radioButton); } myCustomViewPager.setIBack(new IMyCustomViewPagerBack() { @Override public void backMethod(int index) { // Toast.makeText(MainActivity.this, "index:" + index, Toast.LENGTH_SHORT).show(); radioGroup.getCheckedRadioButtonId(); radioGroup.check(index); } }); radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { myCustomViewPager.toScroller(i); } });