自定义控件: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() {// 手势滑动@Overridepublic 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());}// 测量布局宽高@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 手动测量所有孩子的宽高, 解决测试页面无法展示的bugint 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);}// 设置布局位置@Overrideprotected 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());}}@Overridepublic 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后,系统会不断回调此方法@Overridepublic 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@Overridepublic 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@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {return super.dispatchTouchEvent(ev);}
}

自定义控件:Viewpager相关推荐

  1. Android 自定义控件 ViewPager头部指示器控件 ViewPagerBelowIndicator

    效果 演示 说明 为了实现 ViewPager 切换 Fragment 时的标签效果(类似新闻客户端导航的效果) 代码 package com.demo.view;import android.con ...

  2. Android自定义控件之RecyclerView打造万能ViewPager TabLayout(仿今日头条Tab滑动、Tab多布局、indicator蠕动、自定义indicator、文字颜色渐变)

    文章目录 GitHub:https://github.com/AnJiaoDe/TabLayoutNiubility 该轮子特异功能如下: 使用方法 注意:该轮子适用于androidx中的ViewPa ...

  3. 自定义控件(视图)2期笔记03:自定义控件之使用系统控件(优酷案例之广告条Viewpager)...

    1.首先我们看看运行效果,如下: 2. 下面就是详细实现这个效果的过程: (1)新建一个Android工程,命名为"广告条的效果",如下: (2)这里用到一个控件ViewPager ...

  4. Android 自定义控件玩转字体变色 打造炫酷ViewPager指示器

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/44098729,本文出自: [张鸿洋的博客] 1.概述 本篇博客的产生呢,是因为 ...

  5. Android 自定义控件玩转字体变色 打造炫酷ViewPager指示器

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 转载请标 ...

  6. android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...

    转载:http://blog.csdn.net/xiabing082/article/details/48781489 1.  大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...

  7. Android自定义控件之轮播图控件

    背景 最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码.于是自己封装了一下.这里只是做了下封装成一个控件 ...

  8. android自定义控件 几种方式总结

    方式1:不继承任何组件 , 直接在代码里面调用实例化. public class ProgressDialog { private Dialog dialog; public ProgressDial ...

  9. android 滚动画画,Android利用ViewPager实现可滑动放大缩小画廊效果

    画廊在很多的App设计中都有,如下图所示: 该例子是我没事的时候写的一个小项目,具体源码地址请访问https://www.easck.com/> 使用方式 布局中添加该自定义控件 xmlns:t ...

最新文章

  1. \\ n和\\ r之间的区别?
  2. CCS v5 无法启动解决办法及Launchpad仿真器电脑无法识别解决方法
  3. python随机生成100内的10个整数_用python随机生成数字教程_如何用Python编程随机产生10个随机整数,并输出这10个整数的和�9�3...
  4. 201521123023《Java程序设计》第13周学习总结
  5. 谁说烟草公司做不好数字化转型!通过BI工具,一年节约成本79万
  6. unity3d 求两个点长度_用Scratch3.0模拟求π的近似值(二) #寻找真知派#
  7. 那一天,那一月,那一年,那一世,那一瞬
  8. 嵌入式基础面八股文——孤儿进程、僵尸进程、守护进程的概念(3)
  9. 中保车服灾备云,为保险公司“上保险”
  10. 格式工厂 wav 比特率_智能音乐格式转换
  11. Charles 4.2.7 for Mac 中文破解版
  12. snmp中的MIB主要节点含义
  13. xtu 1369 Black White Chess
  14. oracle create table parallel,使用oracle parallel
  15. 高数 | 函数可导和函数连续可导
  16. P1138 第k小整数
  17. C# 获取电脑序列号和主板序列号
  18. 整理各种模板(准备随时弃坑)
  19. C Primer Plus学习笔记(二)- 数据和C
  20. R语言使用lm函数构建简单线性回归模型(建立线性回归模型)、拟合回归直线、可视化散点图并添加简单线性回归直线、添加模型拟合值数据点、添加拟合值点和实际数据点之间的线段表示残差大小、col参数自定义设置

热门文章

  1. Visual Studio 2015 安装
  2. (补充)爬取大西洋月刊并调用彩云小译翻译 API 脚本
  3. dataTables基础函数变量
  4. Log4Net 配置
  5. 卷积神经网络中的参数计算
  6. oracle中将number类型毫秒值转为时间类型
  7. Java基础之一组有用的类——生成日期和时间(TryDateFormats)
  8. Entity Framework 的 edmx xml 文档解析
  9. 转]网络上收集的Visual Studio 2008的一些小技巧
  10. JS收集:限制输入格式