自定义仿Viewpager
来源:互联网 发布:大数据是一种思维方式 编辑:程序博客网 时间:2024/06/05 23:53
自定义仿Viewpager
public class MyViewPager extends ViewGroup { /** * 手势识别器 * 在onTouchEvent方法中把事件传递给手势识别器 */ private GestureDetector detector; /** * 当前页面的下标位置 */ private int currentIndex; /** * 起始坐标位置 */ private float startX; public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(final Context context) { /** * 实例化手势识别器 */ detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {// /**// * 长按// * @param e// */// @Override// public void onLongPress(MotionEvent e) {// super.onLongPress(e);// Toast.makeText(context, "长按", Toast.LENGTH_SHORT).show();// }//// /**// * 双击// * @param e// * @return// */// @Override// public boolean onDoubleTap(MotionEvent e) {// Toast.makeText(context, "双击", Toast.LENGTH_SHORT).show();// return super.onDoubleTap(e);// } /** * 滑动 * @param e1 按下 * @param e2 放开 * @param distanceX 横坐标滑动的距离 * @param distanceY 纵坐标滑动的距离 * @return */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { /** * 通过此方法实现滑动 */ scrollBy((int) distanceX, 0); return true; } }); } /** * 布局 * * @param changed * @param l 左上角横坐标 * @param t 左上角纵坐标 * @param r 右下角横坐标 * @param b 右下角纵坐标 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 遍历子View并为其指定在屏幕的坐标位置 for (int i = 0; i < getChildCount(); i++) { View childAt = getChildAt(i); childAt.layout(i * getWidth(), 0, (i + 1) * getWidth(), getHeight()); } } /** * 测量 * 根据widthMeasureSpec求得宽度width和父View给的模式 * 根据自身宽度width和自身的padding值相减,求得子view可以获得的宽度newWidth * 根据newWidth和模式求得一个新的MeasureSpec值: * MeasureSpec.makeMeasureSpec(newSize,newMode); * 用新的MeasureSpec来计算子View * * @param widthMeasureSpec 父层视图给当前视图的宽和模式 * @param heightMeasureSpec 系统测量时测量多次 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeW = MeasureSpec.getSize(widthMeasureSpec); int modeW = MeasureSpec.getMode(widthMeasureSpec); int sizeH = MeasureSpec.getSize(heightMeasureSpec); int modeH = MeasureSpec.getMode(heightMeasureSpec); Log.e("sizeW=", sizeW + ""); Log.e("modeW=", modeW + ""); Log.e("sizeH=", sizeH + ""); Log.e("modeH=", modeH + ""); for (int i = 0; i < getChildCount(); i++) { View childAt = getChildAt(i); // 测量每个子View的宽高 childAt.measure(widthMeasureSpec, heightMeasureSpec); } } /** * 事件的分发 * Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件 * 还是继续分发给子控件处理 * 返回true表示不继续分发,事件没有被消费,返回false则继续向下分发 * 如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截 * * @param ev * @return */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { //TODO 条件 // 将事件分发给孩子 //getChildAt(0).dispatchTouchEvent(ev); return super.dispatchTouchEvent(ev); } private float downX; private float downY; /** * 事件的拦截 * 该方法是ViewGroup特有的方法,负责事件的拦截 * 返回true表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理 * 返回false则不拦截继续往下传递 * * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { detector.onTouchEvent(ev); //防止突然闪动 //默认传递给孩子 boolean result = false; switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: Log.e("onInterceptTouchEvent", "ACTION_DOWN"); // 记录坐标 downX = ev.getX(); downY = ev.getY(); break; case MotionEvent.ACTION_MOVE: Log.e("onInterceptTouchEvent", "ACTION_MOVE"); // 记录结束值 float endX = ev.getX(); float endY = ev.getY(); // 计算绝对值 float distanceX = Math.abs(endX - downX); float distanceY = Math.abs(endY - downY); if (distanceX > distanceY && distanceX > 5) { //如果横向移动距离大于纵向移动距离则拦截事件 result = true; } break; case MotionEvent.ACTION_UP: Log.e("onInterceptTouchEvent", "ACTION_UP"); break; } return result; } /** * 触摸事件 * 用于事件的处理,返回true表示消费处理当前事件,返回false则不处理 * 交给子控件继续分发 * * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); // 把事件传递给手势识别器 detector.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.e("onTouchEvent", "ACTION_DOWN"); startX = event.getX(); break; case MotionEvent.ACTION_MOVE: Log.e("onTouchEvent", "ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e("onTouchEvent", "ACTION_UP"); float endX = event.getX(); int tmpIndex = currentIndex; if ((startX - endX) > getWidth() / 2) { // 显示下一个页面 tmpIndex++; } else if ((endX - startX) > getWidth() / 2) { tmpIndex--; } /** * 根据下标位置移动到指定页面 */ scrollToPager(tmpIndex); break; } return true; } /** * 屏蔽非法值,根据位置移动到指定页面 * * @param tmpIndex */ private void scrollToPager(int tmpIndex) { if (tmpIndex < 0) { tmpIndex = 0; } if (tmpIndex > getChildCount() - 1) { tmpIndex = getChildCount() - 1; } //当前变量的下标位置 currentIndex = tmpIndex; /** * 手放开后自动完成滑动 * */ //float distanceX = currentIndex*getWidth()-getScrollX();// scrollTo(currentIndex*getWidth(),0); /** * 使用数值发生器完成剩下的滑动 */ ValueAnimator valueAnimator = ValueAnimator.ofInt(getScrollX(), currentIndex * getWidth()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Integer value = (Integer) animation.getAnimatedValue(); scrollTo(value, 0); } }); valueAnimator.setDuration(500).start(); }}
阅读全文
0 0
- 自定义仿Viewpager
- 自定义控件:仿ViewPager实现左右滑动
- 自定义HorizontalScrollView视图实现仿ViewPager效果
- 仿ViewPager
- android 仿viewpager滑动效果自定义升级版
- 用viewpager+fragment实现仿华为自定义铃声
- Android开发-自定义View-AndroidStudio(十)仿ViewPager(1)
- Android开发-自定义View-AndroidStudio(十二)仿ViewPager(2)
- Android开发-自定义View-AndroidStudio(十三)仿ViewPager(3)
- 自定义tab,viewpager实现仿tablayout切换效果
- ViewPager仿淘宝广告栏
- 仿ViewPager效果二
- 仿豌豆荚ViewPager下拉
- 仿豌豆荚ViewPager下拉
- viewpager自定义
- 自定义Viewpager
- 自定义ViewPager
- 自定义viewpager
- 解决windows安装jekyll时的问题
- C6678多核DSP开发——imglib应用之边缘检测
- 关于class.getResourceAsStream() 与class.getClassLoader().getResourceAsStream()区别
- 0519 G2n#W2A-B 盐水的故事
- 【React Native系列教程】Mac(OSX)平台搭建React Native开发环境
- 自定义仿Viewpager
- JNI开发之JNI实践
- Shell脚本基础1-先清楚几个概念
- 计蒜客 灌溉 (最小生成树之prim算法)
- Hibernate 的三种查询方式:HQL、Criteria、Sql
- centos安装redis——(架构篇)
- (体会不同的编程思想的效率差异)A and B and Compilation Errors (看完题先思考如何解决更好)
- webpack+gulp实现自动构建部署
- 格式化输出