code小生 一個專注大前端領域的技術平台公衆号回複
Android
加入安卓技術群
作者:donkingliang
連結:https://www.jianshu.com/p/0783b0a37fa1
聲明:本文已獲
授權發表,轉發等請聯系原作者授權
donkingliang
在開發項目的時候,有時候會遇到一些比較複雜的頁面,需要多個不同的清單或者滑動布局、甚至是
WebView
,組成一個完整的頁面。要實作這樣一個複雜的頁面,在以前我們可能會通過布局嵌套的方式,在一個大的
ScrollView
下嵌套多個
RecyclerView
、
WebView
、
ScrollView
來實作。但是這種嵌套的方式不僅會嚴重影響布局的性能,而且處理滑動事件的沖突也是一件頭疼的事,處理不好會嚴重影響使用者操作的體驗。
ConsecutiveScrollerLayout
正是為了解決這個難題而設計的滑動布局,它可以同時嵌套多個滑動布局(RecyclerView、WebView、ScrollView等)和普通控件(TextView、ImageView、LinearLayou、自定義View等),它把所有的子View看作是一個整體,由
ConsecutiveScrollerLayout
來統一處理布局的滑動,使得多個滑動布局就像一個整體一樣連續滑動,它的效果就像是一個
ScrollView
一樣。而且它支援嵌套所有的View,具有很好的通用性。
使用者不需要關心它是如何滑動的,也不需要考慮滑動的沖突問題,并且不用擔心它會影響子
View
的性能。
下面是對
ConsecutiveScrollerLayout
的使用介紹和一寫注意事項。
項目位址:https://github.com/donkingliang/ConsecutiveScroller
ConsecutiveScroller的設計思路和源碼分析:https://www.jianshu.com/p/34d2c5cdb3fb
效果圖
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYWan5CMhVWO1MWZxIWO5MmN5QGO2gzM0UTNwUTNkNTYxE2Mw8CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
sample.gif
sticky.gif
引入依賴
在Project的build.gradle在添加以下代碼
在Module的build.gradle在添加以下代碼
注意:如果你準備使用這個庫,請務必認真閱讀下面的文檔。它能讓你了解ConsecutiveScrollerLayout可以實作的功能,以及避免不必要的錯誤。
基本使用
ConsecutiveScrollerLayout的使用非常簡單,把需要滑動的布局作為ConsecutiveScrollerLayout的直接子View即可。
關于margin
ConsecutiveScrollerLayout支援左右margin,但是不支援上下margin,子View間的間距可以通過Space設定。
布局對齊方式
ConsecutiveScrollerLayout
的布局方式類似于垂直的
LinearLayout
,但是它沒有gravity和子
view layout_gravity
屬性。
ConsecutiveScrollerLayout
為它的子view提供了
layout_align
屬性,用于設定子view和父布局的對齊方式。layout_align有三個值:左對齊(LEFT) 、右對齊(RIGHT) 和中間對齊(CENTER)。
嵌套Fragment
要想把一個
Fragment
嵌套在
ConsecutiveScrollerLayout
裡。通常我們需要一個布局容器來承載我們的Fragment,或者直接把Fragment寫在activity的布局裡。如果Fragment是垂直滑動的,那麼承載Fragment的容器需要是
ConsecutiveScrollerLayout
,以及Fragment的根布局也需要是垂直滑動的。我們推薦使用
ConsecutiveScrollerLayout
或者其他可垂直滑動的控件(比如:RecyclerView、NestedScrollView)作為Fragment的根布局。如果你的Fragment不是垂直滑動的,則可以忽略這個限制。
布局吸頂
要實作布局的吸頂效果,在以前,我們可能會寫兩個一摸一樣的布局,一個隐藏在頂部,一個嵌套在
ScrollView
下,通過監聽
ScrollView
的滑動來顯示和隐藏頂部的布局。這種方式實作起來既麻煩也不優雅。
ConsecutiveScrollerLayout
内部實作了子View吸附頂部的功能,隻要設定一個屬性,就可以實作吸頂功能。而且支援設定多個子View吸頂,後面的View要吸頂時會把前面的吸頂View推出螢幕。
常駐吸頂
如果你不希望吸頂的view被後面的吸頂view頂出螢幕,而且多個吸頂view排列吸附在頂部,你可以設定常駐吸頂模式:app:isPermanent="true"。
關于吸頂功能的其他方法
局部滑動
ConsecutiveScrollerLayout
将所有的子View視作一個整體,由它統一處理頁面的滑動事件,是以它預設會攔截可滑動的子View的滑動事件,由自己來分發處理。并且會追蹤使用者的手指滑動事件,計算調整
ConsecutiveScrollerLayout
滑動偏移。如果你希望某個子View自己處理自己的滑動事件,可以通過設定
layout_isConsecutive
屬性來告訴父View不要攔截它的滑動事件,這樣就可以實作在這個View自己的高度内滑動自己的内容,而不會作為
ConsecutiveScrollerLayout
的一部分來處理。
在這個例子中
NestedScrollView
希望在自己的高度裡滑動自己的内容,而不是跟随
ConsecutiveScrollerLayout
滑動,隻要給它設定
layout_isConsecutive="false"
就可以了。而
LinearLayout
雖然不是滑動布局,但是在下面嵌套了個滑動布局
RecyclerView
,是以它也需要設定
layout_isConsecutive="false"
。
ConsecutiveScrollerLayout
支援
NestedScrolling
機制,如果你的局部滑動的view實作了
NestedScrollingChild
接口(如:RecyclerView、NestedScrollView等),它滑動完成後會把滑動事件交給父布局。如果你不想你的子view或它的下級view與父布局嵌套滑動,可以給子view設定
app:layout_isNestedScroll="false"
。它可以禁止子view與
ConsecutiveScrollerLayout
的嵌套滑動
滑動子view的下級view
ConsecutiveScrollerLayout
預設情況下隻會處理它的直接子view的滑動,但有時候需要滑動的布局可能不是
ConsecutiveScrollerLayout
的直接子view,而是子view所嵌套的下級view。比如
ConsecutiveScrollerLayout
嵌套
FrameLayout
,
FrameLayout
嵌套
ScrollView
,我們希望
ConsecutiveScrollerLayout
也能正常處理ScrollView的滑動。為了支援這種需求,
ConsecutiveScroller
提供了一個接口:
IConsecutiveScroller
。子view實作
IConsecutiveScroller
接口,并通過實作接口方法告訴ConsecutiveScrollerLayout需要滑動的下級view,
ConsecutiveScrollerLayout
就能正确地處理它的滑動事件。
IConsecutiveScroller
需要實作兩個方法:
在前面提到的例子中,我們可以這樣實作:
public class MyFrameLayout extends FrameLayout implements IConsecutiveScroller {
@Override
public View getCurrentScrollerView() {
// 傳回需要滑動的ScrollView
return getChildAt(0);
}
@Override
public List getScrolledViews() {
// 傳回需要滑動的ScrollView
List views = new ArrayList<>();
views.add(getChildAt(0));return views;
}
}
這樣
ConsecutiveScrollerLayout
就能正确地處理
ScrollView
的滑動。這是一個簡單的例子,在實際的需求中,我們一般不需要這樣做。
注意:
1、getCurrentScrollerView()和getScrolledViews()必須正确地傳回需要滑動的view,這些view可以是經過多層嵌套的,不一定是直接子view。是以使用者應該按照自己的實際場景去實作者兩個方法。
2、滑動的控件應該跟嵌套它的子view的高度保持一緻,也就是說滑動的控件高度應該是match_parent,并且包裹它的子view和它本身都不要設定上下邊距(margin和ppadding)。寬度沒有這個限制。
對ViewPager的支援
如果你的
ViewPager
承載的子布局(或Fragment)不是可以垂直滑動的,那麼使用普通的
ViewPager
即可。如果是可以垂直滑動的,那麼你的ViewPager需要實作
IConsecutiveScroller
接口,并傳回需要滑動的view對象。架構裡提供了一個實作了
IConsecutiveScroller
接口自定義控件:
ConsecutiveViewPager
。使用這個控件,然後你的
ConsecutiveViewPager
的子view(或Fragment的根布局)是可垂直滑動的view,如:RecyclerView、NestedScrollView、ConsecutiveScrollerLayout即可。這樣你的
ViewPager
就能正确地跟
ConsecutiveScrollerLayout
一起滑動了。
布局吸頂時會覆寫在下面的布局的上面,有時候我們希望TabLayout吸頂懸浮在頂部,但是不希望它覆寫遮擋ViewPager的内容。ConsecutiveViewPager提供了setAdjustHeight調整自己的布局高度,讓自己不被TabLayout覆寫。注意:隻有ConsecutiveScrollerLayout是ConsecutiveScrollerLayout的最低部時才能這樣做。
其他注意事項
1、WebView在加載的過程中如果滑動的布局,可能會導緻WebView與其他View在顯示上斷層,使用下面的方法一定程度上可以避免這個問題。
2、
SmartRefreshLayout
和
SwipeRefreshLayout
等重新整理控件可以嵌套
ConsecutiveScrollerLayout
實作下拉重新整理功能,但是
ConsecutiveScrollerLayout
内部嵌套它們來重新整理子view,因為子view時
ConsecutiveScrollerLayout
滑動内容等一部分。除非你給
SmartRefreshLayout
或者
SwipeRefreshLayout
設定
app:layout_isConsecutive="false"
。
3、繼承AbsListView的布局(ListView、GridView等),在滑動上可能會與使用者的手指滑動不同步,推薦使用RecyclerView代替。
4、
ConsecutiveScroller
的
minSdkVersion
是 19,如果你的項目支援19 以下,可以設定:
但是不要在
minSdkVersion
小于 19 的項目使用
AbsListView
的子類,因為
ConsecutiveScrollerLayout
使用了隻有19以上才有的
AbsListView API
。
5、使用
ConsecutiveScrollerLayout
提供的
setOnVerticalScrollChangeListener()
方法監聽布局的滑動事件。View所提供的
setOnScrollChangeListener()
方法已無效。
6、通過
getOwnScrollY()
方法擷取
ConsecutiveScrollerLayout
的垂直滑動距離,View的
getScrollY()
方法擷取的不是
ConsecutiveScrollerLayout
的整體滑動距離。
相關閱讀
1 利用 Android 嵌套滑動機制輕松實作頂部布局置頂
2 玩轉仿探探卡片式滑動效果
3 不使用第三方庫,Bitmap 的優化政策
4 Android 中使用 APT 簡化代碼
5 Android MVP && MVVM深度解析
如果你有寫部落格的好習慣歡迎投稿
點個在看,小生感恩❤️