自定义控件:Viewpager
来源:互联网 发布:土行孙网络加速登录 编辑:程序博客网 时间:2024/05/22 08:41
自定义控件:Viewpager
package com.itheima.myviewpager66;import android.content.Context;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.Scroller;/** * 自定义ViewPager * * 1. 写一个类继承ViewGroup * 2. 重写onLayout方法, 保证孩子正常显示(一字排开) * 3. 重写onTouchEvent, 手势识别器(onScroll),scrollby * 4. 监听手指抬起事件,根据当前滑动后位置,确定下一个页面, scrollTo * 5. 防止pos过大 * 6. 平滑移动, Scroller, startScroll->computeScroll * 7. 增加RadioButton, 监听自定义viewpager页面切换(回调接口),更改raidoButton选中位置 * 8. 监听RadioButton切换事件, 更改页面 * 9. 增加测试页面(ScrollView) * 11. 重写onMeasure,测量每个孩子 * 12. 重写onInterceptTouchEvent, 在适当时机(水平滑动),中断事件传递 * @author Kevin * @date 2015-8-8 */public class MyViewPager extends ViewGroup { // 手势识别器 private GestureDetector mDetector; private Scroller mScroller; public MyViewPager(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(); } public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public MyViewPager(Context context) { super(context); initView(); } private void initView() { mDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { // 手势滑动 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { scrollBy((int) distanceX, 0);// 滑动x,y方向偏移一定距离, 相对位移 // scrollTo(x, y);//绝对位移, 移动到确定的x,y坐标位置 return super.onScroll(e1, e2, distanceX, distanceY); } }); // 初始化滑动器 mScroller = new Scroller(getContext()); } // 测量布局宽高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 手动测量所有孩子的宽高, 解决测试页面无法展示的bug int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } System.out.println("widthMeasureSpec:" + widthMeasureSpec); System.out.println("heightMeasureSpec:" + heightMeasureSpec); int size = MeasureSpec.getSize(widthMeasureSpec); System.out.println("width:" + size); int mode = MeasureSpec.getMode(widthMeasureSpec); //MeasureSpec.AT_MOST; //wrap_content //MeasureSpec.EXACTLY; //确定值 , 宽高写死, 100dp/ match_parent //MeasureSpec.UNSPECIFIED;//没有指定宽高 System.out.println("mode:" + mode); } // 设置布局位置 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 手动设置孩子们的位置, 保证一字排开 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { getChildAt(i).layout(0 + i * getWidth(), 0, (i + 1) * getWidth(), getHeight()); } } @Override public boolean onTouchEvent(MotionEvent event) { mDetector.onTouchEvent(event);// 委托手势识别器处理 switch (event.getAction()) { case MotionEvent.ACTION_UP: // 1.获取当前滑动的位置 // 2.根据当前位置,确定应该跳到第几个页面 // 3.跳到确定页面 int scrollX = getScrollX(); // System.out.println("scrollX:" + scrollX); // 计算应该跳转到下一个页面的哪个位置 int pos = (scrollX + getWidth() / 2) / getWidth(); // //350 / 320 = 1 // int pos = scrollX / getWidth(); // // 350% 320 = 30 // int offset = scrollX % getWidth(); // if (offset > getWidth() / 2) { // pos++; // } // System.out.println("pos:" + pos); // 防止pos过大 if (pos > getChildCount() - 1) { pos = getChildCount() - 1; } // 移动到确定页面 // scrollTo(pos * getWidth(), 0); setCurrentItem(pos); break; default: break; } return true; } // 当调用startScroll后,系统会不断回调此方法 @Override public void computeScroll() { if (mScroller.computeScrollOffset()) {// 判断滑动回调有没有结束 int currX = mScroller.getCurrX();// 获取当前应该移动到的位置 System.out.println("currX:" + currX); scrollTo(currX, 0);// 移动到确定位置 invalidate();// 刷新界面 } } private OnPageChangeListener mListener; public void setOnPageChangeListener(OnPageChangeListener listener) { mListener = listener; } public interface OnPageChangeListener { public void onPageSelected(int position); } /** * 切换到某个具体的页面 * * @param position */ public void setCurrentItem(int pos) { // 平滑的移动到某个位置 int distance = pos * getWidth() - getScrollX();// 目标位置减去当前位置,获得要滑动的距离 // 开始滑动, 滑动时间等于距离绝对值, // 保证距离越长,时间越久(此方法不会产生滑动,而是会导致不断回调computeScroll,需要在这个方法中处理滑动逻辑) mScroller.startScroll(getScrollX(), 0, distance, 0, Math.abs(distance));// 参1:开始x, // 参2:开始y;参3:x偏移,参4:y偏移;参5:滑动时间 invalidate();// 刷新界面,保证滑动器正常运行 // 页面切换的回调 if (mListener != null) { mListener.onPageSelected(pos); } } int startX; int startY; // 事件中断 onInterceptTouchEvent->onTouchEvent @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // 如果左右滑动, 就需要拦截, 上下滑动,不需要拦截 switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mDetector.onTouchEvent(ev);// 将ACTION_DOWN传递给手势识别器, 避免事件丢失 startX = (int) ev.getX(); startY = (int) ev.getY(); 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;// 中断事件传递, 不允许孩子响应事件了, 由父控件处理 } break; default: break; } return false;// 不拦截事件,优先传递给孩子处理 } // 事件分发dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent @Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); }}
0 0
- 自定义控件-ViewPager篇
- 自定义控件:Viewpager
- 自定义Tab + ViewPager控件
- Anroid自定义控件/ScrollView+ViewPager自定义控件
- 自定义控件之viewPager轮播图
- 复杂自定义控件---自定义ViewPager的实现
- Android开发之自定义控件--ViewPager
- Android开发之自定义控件--ViewPager
- 自定义控件---------ViewPager的一个小案例
- 自定义控件:仿ViewPager实现左右滑动
- 自定义控件--广告条(ViewPager)
- Android 自定义控件ViewPager 指示器 ViewPagerIndicator
- 【笔记】自定义控件——ViewPager指示器
- android 系统控件及其自定义---ViewPager
- 简单自定义viewpager,小圆点控件
- Android自定义的轮播图控件,基于ViewPager
- 兼容viewpager中嵌套的viewpager自定义控件
- Android自定义控件:将ViewPager封装自己的TabPager控件
- 嵌入式开发环境搭建之安装交叉编译工具链
- 鸭式辨型模仿接口
- directx初第十一卷
- Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled.
- Android分享功能的实现
- 自定义控件:Viewpager
- headfirst设计模式(2)—观察者模式
- 文件上传之Apache commons fileupload使用
- SQL语句中常用关键词及其解释
- mysql 微信用户昵称emoji 完整保存
- Android中的Audio播放:竞争Audio之Audio Focus的应用
- Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
- LeetCode笔记:39. Combination Sum
- C++处理char*字符串的标准函数