自定义View系列(8)--越界回弹ScrollView
来源:互联网 发布:淘宝网mac版下载 编辑:程序博客网 时间:2024/05/21 19:21
难度
中等
效果说明
越界回弹的效果不用多说了吧,大家应该都知道, 不知道的看下方效果图。
效果图
特性说明
- 支持阻尼系数
- 支持多指触控
- 支持上拉回弹、下拉回弹
- 支持设置开启/关闭回弹:ENABLED_ALL、ENABLED_TOP、ENABLED_BOTTOM 、ENABLED_NONE
- 不影响原有手势的分发处理
- 支持设置最大滑动距离
- 支持设置插值器
实现原理
整体采用offsetTopAndBottom()
+ValueAnimator
实现。
事件分发处理
重写dispatchTouchEvent(MotionEvent ev)
方法,在ACTION_DOWN
中判断是否可以下拉或者上拉,如果可以,就拦截此次事件
滑动处理
在ACTION_MOVE
中,计算每次滑动的差值diffY
,然后使用offsetTopAndBottom()
进行滑动
手指抬起处理
在ACTION_UP
中,获取已滑动的距离scrollY
,然后使用ValueAnimator
计算每一帧滑动的距离,最后再次使用offsetTopAndBottom()
进行滑动
多点触控
多点触控其实很简单,都是有套路可寻的,只要单点触控没问题,多点触控其实很好实现,因为虽然是多点触控,但是实际上只有一个手指处于活跃状态。
关于dispatchTouchEvent(MotionEvent ev)
方法
在Android的整个事件传递体系中,很多人都知道dispatchTouchEvent(MotionEvent ev)
方法是用来分发事件的,分发后的事件如果由自身处理,则需要重写 onTouchEvent(MotionEvent ev)
进行相关操作,但有时候这种方式很麻烦,特别是在我们继承已有的Layout时,比如ScrollView
、FrameLayout
等,
因为这些Layout本身就有一些事件的处理机制,如何在不破坏已有的处理机制的基础上再加上我们自己的处理逻辑,这是一个较为困难的问题。
dispatchTouchEvent(MotionEvent ev)
方法要先于onInterceptTouchEvent(MotionEvent ev)
方法执行,我们可以在dispatchTouchEvent(MotionEvent ev)
方法中处理一些拦截逻辑,这比在onInterceptTouchEvent(MotionEvent ev)
方法中处理拦截逻辑有时候会更好。因为在dispatchTouchEvent(MotionEvent ev)
方法中我们可以同时处理事件的拦截以及view的滑动等操作。当然要使用哪一个方法还要视具体情况而定。
在继承ScrollView时,我们既要保证原有的ScrollView的逻辑不变,还要在此基础上添加我们自己的逻辑,使用dispatchTouchEvent(MotionEvent ev)
是一个比较好的选择。
核心代码
@Override public boolean dispatchTouchEvent(MotionEvent ev) { int action = ev.getAction() & MotionEvent.ACTION_MASK; switch (action) { case MotionEvent.ACTION_DOWN: if (mAnimator.isStarted()) mAnimator.cancel(); mActivePointerId = ev.getPointerId(0); mLastY = (int) ev.getY(); canPullDown = isCanPullDown(); canPullUp = isCanPullUp(); break; case MotionEvent.ACTION_MOVE: final int y = (int) ev.getY(ev.findPointerIndex(mActivePointerId)); int diffY = y - mLastY; if ((canPullUp || canPullDown)) { ViewParent parent = getParent(); if (parent != null) parent.requestDisallowInterceptTouchEvent(true); move(diffY); } mLastY = y; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: if (canPullDown || canPullUp) { final int scrollY = mChild.getTop(); mLastFrameValue = scrollY; mAnimator.setIntValues(scrollY, 0); mAnimator.start(); } mActivePointerId = MotionEvent.INVALID_POINTER_ID; break; case MotionEvent.ACTION_POINTER_DOWN: final int downActionIndex = ev.getActionIndex(); mLastY = (int) ev.getY(downActionIndex); mActivePointerId = ev.getPointerId(downActionIndex); break; case MotionEvent.ACTION_POINTER_UP: final int upActionIndex = ev.getActionIndex(); final int pointerId = ev.getPointerId(upActionIndex); if (pointerId == mActivePointerId) { final int newPointerIndex = upActionIndex == 0 ? 1 : 0; mActivePointerId = ev.getPointerId(newPointerIndex); } mLastY = (int) ev.getY(ev.findPointerIndex(mActivePointerId)); break; } super.dispatchTouchEvent(ev);//分发父view的事件 return true; }
以上是实现整个效果的核心代码,更多详细处理逻辑请移步至PopularEffect。
PopularEffect是一个汇集各种效果的仓库,除此之外,还对每种效果的实现方式都做了剖析,并编写了对应的样例。虽然仓库已经建立了快一年,但实际上并没有精力去维护,现在打算把它维护起来,我只要有时间,都会尽量添加一些效果分析和样例,虽然只有我一个人维护这个仓库,注定速度上会很慢(分析效果以及编写样例是最为费时费力的),但我相信水滴石穿! 感兴趣的可以stat一波(手动滑稽)。
- 自定义View系列(8)--越界回弹ScrollView
- Android自定义View--ScrollView实现回弹效果
- 自定义scrollview 回弹效果
- 自定义ScrollView加回弹效果
- 自定义scrollview实现下拉回弹
- Scrollview回弹效果自定义控件
- 自定义控件之ScrollView回弹效果
- 自定义ScrollView实现放大回弹效果
- 回弹ScrollView
- 自定义ScrollView 下拉上拉回弹,阻尼效果
- Android 自定义最简单的ScrollView,附带拉动回弹
- 自定义View(四)--自定义ScrollView
- 自定义下拉回弹View-掌握View冲突处理
- TwinklingRefreshLayout 支持下拉刷新和上拉加载的 RefreshLayout,自带越界回弹效果,支持 RecyclerView,AbsListView,ScrollView,We
- TwinklingRefreshLayout 支持下拉刷新和上拉加载的 RefreshLayout,自带越界回弹效果,支持 RecyclerView,AbsListView,ScrollView等
- ScrollView拖动回弹效果
- ScrollView 回弹特效
- NGUI ScrollView 回弹控制
- C# 中的数组类
- 50个必考SQL语句基础常用面试必备
- Python基本数据类型
- 第一周第一节课 :什么是数据结构
- 如何制作一张海报
- 自定义View系列(8)--越界回弹ScrollView
- tomcat 发布简单的html网站
- 斯坦福大学2017年-Spring-最新强化学习(Reinforcement Learning)课程分享
- VMware Workstation 8.0的安装
- 牛客网 剑指offer-二进制中1的个数
- 寒假学习之stm32(15)----DMA(direct memory access)
- 47.Scala多重界定代码实战及其在Spark中的应用源码解析
- 求解最大子序列和问题的线性时间算法
- firewall常用操作示例: