仿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.pswp.cn/news/251743.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251743.shtml
英文地址,請注明出處:http://en.pswp.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;主題對象則通知所有的觀察者對象&#…