Android View滑动处理大法

这篇具有很好参考价值的文章主要介绍了Android View滑动处理大法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原文链接 Android View滑动处理大法

对于触控式操作来说,滑动是一个特别重要的手势操作,如何做到让应用程序的页面滑动起来如丝般顺滑,让用户感觉到手起刀落的流畅感,是开发人猿需要重点解决的问题,这对提升用户体验是最为重要的事情。本文就将探讨一下,Android中View的滑动相关知识,以及如何做到丝般顺滑。

Android View滑动处理大法,android,Android,android-studio,android studio

如何让View滑动起来

View的滑动是GUI支持的一项基本特性,就像触摸事件一件,这是废话,平台如果不支持,你还搞个毛线。

View滑动的基本原理

我们先来看一下Android中实现View的滑动的基本原理。其实屏幕并没有动啊,一个View的可绘制区域,对于屏幕来说,对于view tree来说都是没有变化 的。父布局给某一个View的绘制区域是在layout之后就确定好了的,当View的真实高度或者宽度超过了这块可绘制区域,那么就需要滑动才可以把整个View做到用户可见。View内部通过两个关键成员变量mScrollX和mScrollY来记录滑动之后的坐标,View本身有mLeft和mTop来标识自己相对于父布局的坐标位置,那么当有滑动的时候,在此View当中具体要绘制的区域就变成了以mLeft+mScrollX和mTop+mScrollY为起点的区域了。由此View便滚动起来了。

如何实现View的滑动

对于开发人猿来说,实现View的滑动,需要关注三个重要的方法,也即是View#scrollBy,View#scrollTo以及View#onScrollChanged,这是实现滑动的三个最为核心的方法。

scrollBy提供的参数是需要滑动的距离,而scrollTo则是需要传入要滑动到的目标坐标值,这两个方法都是要修改mScrollX和mScrollY的值,本质上是一样的。而onScrollChanged则是一个回调,用以通知更新了的滑动位置。

Scroll手势

要想让View滑动起来,离不开事件手势的支持。最简单也是最直接的手势就是onScroll手势,这个在GestureDetecor中可以识别出此手势,或者自己去直接处理touch event也可以得出此手势。这个并不复杂,就是直接通过touch 事件来计算滑动多少距离就好了,按照View预设计的可以滑动的方向,比如横向就计算不同时间点MotionEvent的坐标值,得到一个水平距离deltaX,然后调用scrollBy即可。垂直方向依此类推。

Android View滑动处理大法,android,Android,android-studio,android studio

Scroll手势简单是因为它是直接来源于事件,且速度较慢,并不需要额外处理,所以整体逻辑处理流程并不复杂。

在GestureDetector中的识别就是在ACTION_MOVE时,查看滑动过的距离,这个距离(由sqrt(dx x dx, dy x dy)如果大于touch slop,就会触发onScroll手势回调。

Fling手势

Fling也即是快速滑动,就是手指在屏幕上使劲的『挠』一下,手势的要点是手指在屏幕快速滑过一小段短距离,就像把一个小球弹出去的感觉一样。对于Fling手势来说,最重要的是速度,水平方向的速度和垂直方向的速度,可以理解为高中物理常讲到的平抛运动一样。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zolPYiCN-1688998312494)(https://ts1.cn.mm.bing.net/th/id/R-C.16bf196415d4a9adb260a465059753cf?rik=iJZkKq8qecE9ew&riu=http%3a%2f%2fwww.androidpolice.com%2fwp-content%2fuploads%2f2017%2f05%2fnexus2cee_fling-animation.gif&ehk=FJQxdKhU05GazX23tULh7WVJ3Spv1upP6zHbMY8s9YA%3d&risl=&pid=ImgRaw&r=0)]

GestureDetector识别Fling的逻辑是,在ACTION_UP时,检查此次事件的速度,如果水平方向速度或者垂直方向速度超过了阈值,便会触发Fling手势回调。

注意:留意Scroll与Fling的区别,Scroll是慢的,不关心时间与速度,只关心滑动的距离,是在ACTION_MOVE时,手指并未有离开屏幕时就触发了,只要是ACTION_MOVE还在继续,就会继续触发onScroll,并且ACTION_UP时终止整个Scroll,而Fling只关心速度,不关心距离,是在ACTION_UP时,手指离开了屏幕了(此次事件流处理结了)才会触发。

VelocityTracker

Fling事件速度是决定性的,仔细看GestureDetector的处理过程会发现它使用了一个叫做VelocityTracker的对象,来帮忙处理一些关于速度的具体逻辑,那么有必要深入了解一下这个对象。

VelocityTracker使用起来并不复杂,获取它的一个对象后,只需要不断的把MotionEvent塞给它就可以了,然后在需要的时候让其计算两个方向上的速度,然后就没有然后了:

    velocityTracker = VelocityTracker.obtain();
    
    onTouchEvent(MotionEvent ev) {
        velocityTracker.addMovement(ev);
        
        if (want to know velocities) {
           velocityTracker.computeCurrentVelocity(100);
           vx = velocityTracker.getXVelocity();
           vy = veolocityTracker.getYVelocity();
           be happy with vx and vy.
        }
     }

这个类的实现,值得仔细看一下,它主要的实现都是用JNI去实现,可能是因为计算方式较复杂,所以computeCurrentVelocity方法也说明了,让你真用的时候再调,这个不用去管细节实现。重点看一下这个类,里面有一个对象池,用以缓存对象,并且创建对象的方式并不是直接new,而是用其obtain方法。这里用的是叫享元(Flyweight Pattern)的设计模式,也就是说VelocityTracker对象其实是共享的。

顺滑如丝

前面提到了,让View滑动,只需要调用scrollBy或者scrollTo即可,但这个吧,是直接修改了mScrollX,mScrollY,然后invalidate,View下次draw时就直接在把目标区域内容绘制出来了,换句话说这两个方法滑动是瞬间跳格式的。

一般来说,这也没有问题,就像onScroll手势,ACTION_MOVE时,不断的scrollBy刚刚滑过的距离,都还okay,没有什么问题。

但是对于Fling事件就不行了,Fling事件,也即快速滑动,要求短时间内进行大距离滑动,或者像有跳转的需求时,也是短时间内要滑动大距离。如果直接scrollBy或者scrollTo一步到位了,会显得 相当的突兀,体验相当不好,卡顿感特别强。如果能像做动画那样,在一定时间内,让其平滑的滑动,就会如丝般顺滑,体验好很多。Scroller就是专门用来解决此问题的。

Scroller

Scroller是对滑动的封装,并不是View的子类,其实它跟View一点关系也没有,也不能操作View,实际上它与属性动画类似,它仅是一个滚动位置的计算器,告诉它起始位置和要滚动的距离,然后它就会告诉你位置随时间变化的值。其实这是一个中学物理题,也即给定初始位置,给定要滚动的距离,以一定的方式来计算每个时间点的位置。具体的计算方式由mInterpolater成员来控制,默认是ViscousFluid,是按自然指数为减速度来计算的,具体的可以查看Scroller的源码。如果不喜欢默认的计算方式,可以自己实现个Interpolator,然后在构造时传进去。

Scroller的作用在于实现平稳滑动,不让View的滚动出现跳跃,比如滑动一下ListView,开始滑动时的位置是x0,y0(ActionDown的位置),要向下滑动比如500个像素,不平稳的意思是,从x0,一下跳到x0+500的位置。要平稳,就要不断的一点点的改变x的值然后invalidate,这也就是Scroller的典型使用场景:

Scroller scroller = new Scroller(getContext());
scroller.startScroll(x0, y0, 500, 0);

然后在computeScroll时:

if (scroller.computeScrollOffset()) {
   int currX = scroller.getCurrX();
   int currY = scroller.getCurrY();
   invalidate(); // with currX and currY
}

computeScrollOffset在滚动没结束时返回true,也就是说你需要继续刷新view。返回false时表明滚动结束了,当然也就没有必要再刷新view(当然如果你乐意也可以继续刷,但是位置啥的都不变了,所以刷了也白刷)。

滑动冲突处理

关于View的滑动,最难搞的问题便是手势冲突处理,特别是当页面的结构变得复杂了以后。一般来讲,滑动手势,是让某一个View沿着某一个方向『平移』一段距离,如果某一个页面中只有一个View是可以滑动的,或者页面中不同的View的可滑动方向是垂直正交的,那么就不会有冲突的问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bmf47f23-1688998312494)(https://ts1.cn.mm.bing.net/th/id/R-C.0b4a444cd44ddeebce726777cdddf2f9?rik=Wrup7%2bYTmIZibA&riu=http%3a%2f%2funitid.nl%2fandroidpatterns%2fwp-content%2fuploads%2fscrollthumb.png&ehk=hHYe%2byE4JOmZrc8S4vLHliUmVEJ%2f6uI3oeHeg8s0dMM%3d&risl=&pid=ImgRaw&r=0)]

所谓滑动冲突,是指父View和子View都接受滑动手势,并且方向又是一样的,这时就产生了滑动冲突,常见就是ScrollView中套着ListView(这个通常是垂直Y方向上面有滑动冲突),或者ViewPager中套着ScrollView(这个是水平X方向上有滑动冲突)。

要想解决好滑动冲突问题,需要先确实好整体的设计方案,有了大的原则后,就容易用技术方案找到解法。最理想的方案,也是目前用的最多的方案就是在子View的边界设定一个margin区域,当ACTION_DOWN在margin区域以外,认定滑动手势归父View处理,否则交由子View处理。像一些全局手势也是要用如此的方案,当点击距离屏幕一定范围内(margin区域)认定此事件归当前页面处理,否则就认定为全局手势,就好比从屏幕左边向右滑动,很多应该将此识别为BACK到上一页,但如果离左边较远时滑动,就会是页面内部的滑动事件(假如它有可滑动的组件的话,事件手势会被其滑消耗掉)。文章来源地址https://www.toymoban.com/news/detail-547398.html

参考资料

  • Detect common gestures
  • Flyweight pattern
  • Design Patterns - Flyweight Pattern
  • Animate a scroll gesture
  • Android Scroller simple example

原创不易,打赏,点赞,在看,收藏,分享 总要有一个吧

到了这里,关于Android View滑动处理大法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android进阶 View事件体系(三):典型的滑动冲突情况和解决策略

    本篇文章为总结View事件体系的第三篇文章,前两篇文章的在这里: Android进阶 View事件体系(一):概要介绍和实现View的滑动 Android进阶 View事件体系(二):从源码解析View的事件分发 本篇文章主要是介绍两种基本的滑动冲突情况和对应的解决策略,内容有: 基本的滑动冲突

    2024年02月10日
    浏览(37)
  • Android Studio实现滑动图片验证码

    源代码链接 效果: MainActivity SlideImageView activity_main.xml

    2024年02月13日
    浏览(45)
  • Android Studio 之 Android 中使用 HanLP 进行句子段落的分词处理(包括词的属性处理)的简单整理 Android Studio 之 Android 中使用 HanLP 进行句子段落的分词处理(包括词的属性处理)的简单整理

    目录 Android Studio 之 Android 中使用 HanLP 进行句子段落的分词处理(包括词的属性处理)的简单整理 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、实现步骤 六、关键代码 附录:在 HanLP 中,Term 对象的 nature 字段表示词性 Android 开发中的一些基础操作,使用整理

    2024年02月12日
    浏览(34)
  • android studio “run app”运行app 自行启动失败处理

    1.检查是否因为代码bug导致直接运行崩溃 2.检查是否配置 3.检查studio Edit Configurations 启动配置选项配置(Default Activity)    4.点击studio导航栏\\\"File\\\"  选择Clear cache and restart Android Studio 5.检查你的Android虚拟设备(AVD)设置:如果您正在使用一个模拟器运行您的应用程序,确保AVD设置正

    2024年04月09日
    浏览(42)
  • 【Android】之【View绘制】

    简单的可以说,如 measure,layout,draw 分别对应测量,布局,绘制三个过程。 ① measure:测量。系统会先根据xml布局文件和代码中对控件属性的设置,来获取或者计算出每个View和ViewGrop的尺寸,并将这些尺寸保存下来。 ② layout:布局。根据测量出的结果以及对应的参数,来确

    2024年02月08日
    浏览(36)
  • Android View动画整理

    View 动画相关内容可参考官网 动画资源 此前也有写 View 动画相关的内容,但都只是记录代码,没有特别分析。以此篇作为汇总、整理、分析。 Android View 动画有4中,分别是 平移动画 TranslateAnimation 缩放动画 ScaleAnimation 旋转动画 RotateAnimation 透明度动画 AlphaAnimation View 动画可以

    2024年02月11日
    浏览(45)
  • Android自定义View流程

    在开发中,View视图具有非常重要的作用,它是直接呈现给使用者的,因此向用户展示精美高效的View视图很有意义。Android系统提供了丰富的视图组件,如TextView、ImageView、Button等,还提供了RelativeLayout、LinearLayout、FrameLayout等组合组件,使用这些组件搭配能实现良好的视图效果

    2024年04月11日
    浏览(47)
  • android 自定义圆角View

    public class CustomView extends View {     private float cornerRadius;     public CustomView(Context context) {         super(context);         init();     }     public CustomView(Context context, AttributeSet attrs) {         super(context, attrs);         TypedArray typedArray = context.obt

    2024年02月11日
    浏览(46)
  • android viewpager 禁止滑动

    本文介绍了本人有一个相关的需求需要实现这一功能,在过程中发现自己之前没做过,然后记录下实现这一功能的过程及相关的小知识点。 viewpager 禁止滑动,就是在特殊的条件,比如说编辑的状态下,是不允许用户滑动的,但是看了下viewpager 的源码,也百度了一下,并没有

    2024年01月19日
    浏览(46)
  • android 监听webview 滑动方向以及是否滑动到顶部、底部

    判断webview 滑动方向,老生常谈的问题,再次提及。 监听webview是否滑动到底部、顶部,可以通过重新webview的onScrollChanged()或者onTouchEvent()判断。 其中通过重写onTouchEvent()可以判断出webview的滑动方向。 判断是否滑动到底部,是通过判断webview的高度与当前webview的高度做

    2024年02月15日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包