效果图: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); } });