仿MIUI弹性列表

前言

最近去小米之家体验了下小米9,发现MIUI有一个挺特别的列表动画效果,在系统上的各种应用上都能见到它的身影。

网上查了下,小米早在几个系统版本前就有这个,网上也有了实现这个效果的控件库。实现方法大同小异,大多都是通过继承ScrollView,然后重写onInterceptTouchEvent方法和OnTouchEvent方法,计算手指滑动距离来缩放内部控件。

这种方式适合对View触摸分发机制比较熟悉的同学,代码比较复杂,看了下现有的库也都没能实现MIUI中Fling状态的弹性效果。正好最近看了下NestedScrolling的相关知识,发现能很好地实现这些效果,所以就让我们来看看吧。

预备知识

需要先了解下NestedScrollChildNestedScrollParent,所谓的NestedScrolling机制是这样的:内部NestedScrollingChild在滚动的时候,预先将dx,dy通过NestedScrollingChildHelper传递给NestedScrollingParentNestedScrollingParent可先对其进行部分消耗,Parent处理完后,再将剩余的部分还给内部NestedScrollingChild处理,最后再把剩下的dx,dy再给Parent做最后处理,这样一次触摸滑动事件将可以由多个控件共同消耗处理,这样就可以很方便解决之前一次触摸滑动事件只能被一个控件响应而产生的嵌套滑动问题。

先看下NestedScrollParent


public interface NestedScrollingParent {public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);public void onStopNestedScroll(View target);public void onNestedScroll(View target, int dxConsumed, int dyConsumed,int dxUnconsumed, int dyUnconsumed);public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);public boolean onNestedPreFling(View target, float velocityX, float velocityY);public int getNestedScrollAxes();
}
复制代码

先看下NestedScrollingChild

public interface NestedScrollingChild {​void setNestedScrollingEnabled(boolean enabled);​boolean isNestedScrollingEnabled();​boolean startNestedScroll(int axes);​void stopNestedScroll();​boolean hasNestedScrollingParent();​boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);​boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);boolean dispatchNestedPreFling(float velocityX, float velocityY);}
复制代码

可以看到parent和child的api命名很类似,是成对出现的,确实,它们之前存在发起方和接收方的事件调用关系,都是由child先响应滑动触摸实现,通过NestedScrollingChildHelper分发给parent。

弹性列表实现

为方便解析,我们先只实现下滑的弹性动画:

 //子view,需事先NestedScrollingChildprivate var childView: View? = nullprivate val mNestedScrollingParentHelper: NestedScrollingParentHelperprivate var offsetScale = 0fprivate var flingScale = 0fprivate var consumedDy = 0set(value) {field = if (value > 0) {0} else {value}}//是否是Fling滑动private var filing = false//判定滑动的最小距离private var touchSlop: Int = 0private var animator: ValueAnimator? = nullinit {mNestedScrollingParentHelper = NestedScrollingParentHelper(this)touchSlop = ViewConfiguration.get(context).scaledTouchSlop}override fun onFinishInflate() {super.onFinishInflate()childView = getChildAt(0)}/*** 滚动开始*/override fun onStartNestedScroll(child: View, target: View, nestedScrollAxes: Int): Boolean {filing = falseconsumedDy = 0return child === childView && ViewCompat.SCROLL_AXIS_VERTICAL == nestedScrollAxes}/*** 先于child滚动*/override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray) {if (childView!!.scrollY == 0 && (dy < 0 || consumedDy < 0)) {consumedDy += dyif (Math.abs(consumedDy) > touchSlop) {//计算缩放值,最大放大1.3倍offsetScale = (1.3 - 600f / (2000 + Math.pow(Math.abs(consumedDy).toDouble(), 2.0))).toFloat()startBouncingTop()//存放消耗的距离,child会接收consumed[1] = dy}}}override fun onNestedScrollAccepted(child: View, target: View, nestedScrollAxes: Int) {mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes)}/*** 先于child处理Fling*/override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {if (velocityY < 0 && childView!!.scrollY == 0) {filing = trueconsumedDy = (consumedDy + velocityY).toInt()flingScale = (0.3 - 600f / (2000 + Math.pow(Math.abs(consumedDy).toDouble(), 2.0))).toFloat()return true}return false}override fun onNestedFling(target: View, velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {return filing}override fun onStopNestedScroll(target: View) {mNestedScrollingParentHelper.onStopNestedScroll(target)backBouncing(filing)}override fun getNestedScrollAxes(): Int {return mNestedScrollingParentHelper.nestedScrollAxes}/*** 进行回弹*/private fun backBouncing(filing: Boolean) {//初始化if (animator != null && animator!!.isRunning) {animator!!.cancel()animator = null}if (filing) {animator = ValueAnimator.ofFloat(offsetScale, flingScale, 0f)animator!!.duration = 400} else {animator = ValueAnimator.ofFloat(offsetScale, 0f)animator!!.duration = 250}animator!!.interpolator = OvershootInterpolator()animator!!.addUpdateListener {offsetScale = it.animatedValue as FloatstartBouncingTop()}animator!!.start()}/*** 从顶部开始滑动*/private fun startBouncingTop() {childView!!.pivotY = 0fchildView!!.pivotX = 0fchildView!!.scaleY = offsetScale}
复制代码

弹性效果

Fling弹性效果

参考文章

Android 8.0 NestedScrollingChild2与NestedScrollingParent2实现RecyclerView阻尼回弹效果

转载于:https://juejin.im/post/5ce2623f6fb9a07ef3763a90

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251743.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10、angular的全部api

1、lowercase var app angular.module(myApp, []);app.controller(myCtrl, function($scope) { console.log(angular.lowercase(AbCdEf))}); 2、uppercase var app angular.module(myApp, []);app.controller(myCtrl, function($scope) { console.log(angular.uppercas…

JavaScript快速入门-ECMAScript本地对象(String)

一、String对象 String对象和python中的字符串一样&#xff0c;也有很多方法&#xff0c;这些方法大概分为以下种类&#xff1a; 1、索引和查找 1、charAt() 返回指定位置的字符。 2、charCodeAt() 返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。 …

8、angular的select

1、数据源为数组 x for x in names第一个x代表在下拉框内显示的数据 第二个x指的是在names里数据 <!DOCTYPE html><html><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0…

ZOJ4116 Game on a Graph

给一个含n个点 m条边的连通图 把k个人分成两组 轮流拿掉一条边 当取走一条边后图不再连通 这个队就输了 水题啦 边为n-1时 下一个拿掉边的那个组就输啦 AC代码&#xff1a; 1 #include<bits/stdc.h>2 using namespace std;3 typedef long long ll;4 typedef unsigned lon…

集美大学1414班软件工程个人作业2——个人作业2:APP案例分析

一、作业链接 个人作业2&#xff1a;APP案例分析 二、博文要求 通过分析你选中的产品&#xff0c;结合阅读《构建之法》&#xff0c;写一篇随笔&#xff0c;包含下述三个环节的所有要求。 第一部分 调研&#xff0c; 评测 下载软件并使用起来&#xff0c;描述最简单直观的个人第…

全局eslint不生效的处理

react项目里能用上 eslint 的 airbnb 规范真是的&#xff0c;对自己的编码有很好的帮助&#xff0c;不经可以养成良好的代码风格&#xff0c;而且还能检测出 state或者变量 是否 使用过&#xff0c; 然而&#xff0c;所在团队的小伙伴们&#xff0c;却并未使用&#xff0c;或者…

IP通信基础

源端口和目的端口字段--各占2字节。端口是传输层与应用层的服务接口。传输层的复用和分用功能都要通过端口才能实现。序号字段--占4字节。TCP连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号转载于:https://www.…

回溯算法 ------回溯算法的几个例子

1.回溯算法的小结 2.回溯算法的几个例子 2.1 ------ 4后问题 搜索空间&#xff1a; 2.2 ------01背包问题 01背包问题的算法设计 01背包问题的实例分析 01背包问题的搜索空间 2.3 ------- 货郎问题 货郎问题实例 货郎问题的搜索空间 最后再来个小结 转载于:https://www.cnb…

Phaserjs V2的state状态解析及技巧

用phaserjs开发了好多游戏了&#xff0c;但是对phaser还是了解不深&#xff0c;只知道怎么去用&#xff0c;今天就特意花点时间研究下phaser的状态管理到底是怎么回事。 首先&#xff0c;new Phaser.Game&#xff0c;以下是Phaser.Game的部分源码&#xff1a; Phaser.Game fun…

JAVA_出神入化学习路线大纲

注&#xff1a;参考GitHub上的项目&#xff08;toBeTopJavaer&#xff09;总结出来 也是自己的目标。 基础篇&#xff1a;https://www.cnblogs.com/blogzcc/p/10899066.html 进阶篇&#xff1a;https://www.cnblogs.com/blogzcc/p/10899841.html 高级篇&#xff1a;https://www…

Ubuntu安装并使用sogou输入法

1.下载搜狗输入法的安装包 下载地址为&#xff1a;http://pinyin.sogou.com/linux/ ,如下图&#xff0c;要选择与自己系统位数一致的安装包&#xff0c;我的系统是64位&#xff0c;所以我下载64位的安装包 2.按键CtrAltT打开终端&#xff0c;输入以下命令切换到下载文件夹: [ht…

面試題之web

1. django和flask框架的区别&#xff1f; django&#xff1a;大而全的全的框架&#xff0c;重武器&#xff1b;内置很多组件&#xff1a;ORM、admin、Form、ModelForm、中间件、信号、缓存、csrf等 flask: 微型框架、可扩展强&#xff0c;如果开发简单程序使用flask比较快速&am…

python 常用镜像

pip镜像https://pypi.tuna.tsinghua.edu.cn/simplehttps://pypi.douban.io.com/simple pip install python-qt -i https://pypi.tuna.tsinghua.edu.cn/simple清华开源软件镜像&#xff1a;&#xff08;anaconda&#xff09;https://mirrors.tuna.tsinghua.edu.cn/https://mirro…

flutter 几秒前, 几分钟前, 几小时前, 几天前...

Show me the code!!! class RelativeDateFormat {static final num ONE_MINUTE 60000;static final num ONE_HOUR 3600000;static final num ONE_DAY 86400000;static final num ONE_WEEK 604800000;static final String ONE_SECOND_AGO "秒前";static final St…

CMake 使用笔记

记录 CMake 相关知识。 Prelude&#xff1a;读文档一定要有耐心&#xff01; 问题一 CLion&#xff1a; CMakeLists.txt 中 set(CMAKE_CXX_FLAGS -Wall) 不起作用 Solution: 改用 target_compile_options(main PUBLIC -Wall) Reference:target_compile_optionsGCC: Options to …

Docker 完全指南

Docker 最初 dotCloud 公司内部的一个业余项目Docker 基于 Go 语言Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案Docker 的基础是 Linux 容器&#xff08;LXC&#xff09;等技术Docker 容器的启动可以在秒级实现&#xff0c;这相比传统的虚拟机方式要快得多Docker 对…

NOIP 2016【蚯蚓】

好吧&#xff0c;我承认我是个智障…… 这道题一眼看上去就是个堆&#xff0c;然而实际上有单调性。 注意到&#xff0c;如果 \(q 0\) 的话&#xff0c;将蚯蚓的左右两边分开丢进两个队列中&#xff0c;则两个队列都是单调不增的&#xff0c;因为每次取出的蚯蚓长度单调不增。…

Ajax异步(客户端测试)

客户端测试&#xff1a;GET方法实现Ajax异步 var request new XMLHttpRequest(); request.open("GET","sever.php?number" document.getElementById("keyword").value); request.send(); request.onreadystatechange function(){ if(request.…

VS 添加文件添加文件成链接

转载于:https://www.cnblogs.com/wsxkit/p/10907585.html

设计模式——3.观察者模式

观察者模式&#xff08;Observer&#xff09; 观察者模式&#xff08;Observer&#xff09;简介&#xff1a; 定义一个一对多的依赖关系&#xff0c;让多个观察者对象监听某个主题对象&#xff0c;当主题对象的状态发生改变时&#xff0c;主题对象则通知所有的观察者对象&#…