前言
vlayout 的設計思路請參考Tangram 的基礎 —— vlayout(Android)。框架已經開源,歡迎移步到 github上指教。本文介紹 vlayout 的基本使用。
默認實現
- 默認通用佈局實現,解耦所有的View和佈局之間的關係: Linear, Grid, 吸頂, 浮動, 固定位置等。
- LinearLayoutHelper: 線性佈局
- GridLayoutHelper: Grid佈局, 支持橫向的colspan
- FixLayoutHelper: 固定佈局,始終在屏幕固定位置顯示
- ScrollFixLayoutHelper: 固定佈局,但之後當頁面滑動到該圖片區域才顯示, 可以用來做返回頂部或其他書籤等
- FloatLayoutHelper: 浮動佈局,可以固定顯示在屏幕上,但用戶可以拖拽其位置
- ColumnLayoutHelper: 欄格佈局,都佈局在一排,可以配置不同列之間的寬度比值
- SingleLayoutHelper: 通欄佈局,只會顯示一個組件View
- OnePlusNLayoutHelper: 一拖N佈局,可以配置1-5個子元素
- StickyLayoutHelper: stikcy佈局, 可以配置吸頂或者吸底
- StaggeredGridLayoutHelper: 瀑布流佈局,可配置間隔高度/寬度
- 上述默認實現裏可以大致分爲兩類:一是非fix類型佈局,像線性、Grid、欄格等,它們的特點是佈局在整個頁面流裏,隨頁面滾動而滾動;另一類就是fix類型的佈局,它們的子節點往往不隨頁面滾動而滾動。
- 所有除佈局外的組件複用,VirtualLayout將用來管理大的模塊佈局組合,擴展了RecyclerView,使得同一RecyclerView內的組件可以複用,減少View的創建和銷燬過程。
使用
版本請參考mvn repository上的最新版本(目前最新版本是1.0.1),最新的 aar 都會發布到 jcenter 和 MavenCentral 上,確保配置了這兩個倉庫源,然後引入aar依賴:
// gradle
compile ('com.alibaba.android:vlayout:1.0.1@aar') {
transitive = true
}
或者maven
// pom.xml in maven
<dependency>
<groupId>com.alibaba.android</groupId>
<artifactId>vlayout</artifactId>
<version>1.0.1</version>
<type>aar</type>
</dependency>
初始化LayoutManager
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
final VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
設置回收複用池大小,(如果一屏內相同類型的 View 個數比較多,需要設置一個合適的大小,防止來回滾動時重新創建 View):
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
recyclerView.setRecycledViewPool(viewPool);
viewPool.setMaxRecycledViews(0, 10);
更新:看了很多人寫的demo和源碼解析後,需求提醒注意上述示例代碼裏只針對type=0的item設置了複用池的大小,如果你的頁面有多種type,需要爲每一種類型的分別調整複用池大小參數。
加載數據時有兩種方式:
- 一種是使用
DelegateAdapter
, 可以像平常一樣寫繼承自DelegateAdapter.Adapter
的Adapter, 只比之前的Adapter需要多重載onCreateLayoutHelper
方法。 其他的和默認Adapter一樣。
DelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager, hasConsistItemType);
recycler.setAdapter(delegateAdapter);
// 之後可以通過 setAdapters 或 addAdapter方法添加DelegateAdapter.Adapter
delegateAdapter.setAdapters(adapters);
// or
public class CustomAdapter extends DelegateAdapter.Adapter {
......
}
CustomAdapter adapter = new CustomAdapter(data, new GridLayoutHelper());
delegateAdapter.addAdapter(adapter);
更新:hasConsistItemType這個參數有時候容易被人忽略,當hasConsistItemType=true的時候,不論是不是屬於同一個子adapter,相同類型的item都能複用。表示它們共享一個類型。 當hasConsistItemType=false的時候,不同子adapter之間的類型不共享
- 另一種是當業務有自定義的複雜需求的時候, 可以繼承自
VirtualLayoutAdapter
, 實現自己的Adapter
public class MyAdapter extends VirtualLayoutAdapter {
......
}
MyAdapter myAdapter = new MyAdapter(layoutManager);
//構造 layoutHelper 列表
List<LayoutHelper> helpers = new LinkedList<>();
GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4);
gridLayoutHelper.setItemCount(25);
helpers.add(gridLayoutHelper);
GridLayoutHelper gridLayoutHelper2 = new GridLayoutHelper(2);
gridLayoutHelper2.setItemCount(25);
helpers.add(gridLayoutHelper2);
//將 layoutHelper 列表傳遞給 adapter
myAdapter.setLayoutHelpers(helpers);
//將 adapter 設置給 recyclerView
recycler.setAdapter(myAdapter);
在這種情況下,需要使用者注意在當LayoutHelpers
的結構或者數據數量等會影響到佈局的元素變化時,需要主動調用setLayoutHelpers
去更新佈局模式。
Demo
詳細代碼參考:github
擴展布局
如果默認的佈局實現滿足不了,你的需求,可以註冊自定義的LayoutHelper
來實現佈局邏輯。有三種基類可以供你使用:
BaseLayoutHelper
:像LinearLayoutHelper
、GridLayoutHelper
等,內部View可以按行回收的佈局,可直接繼承此類,主要實現layoutViews()
、computeAlignOffset()
等方法。AbstractFullFillLayoutHelper
:有些佈局內部的View 並不是從上至下排列的順序,即 Adatper 裏的數據順序和物理視圖順序不一致,那麼可能就不能按數據順序佈局和回收,需要一次性佈局、一次性回收。主要實現layoutViews()
等方法。可參考OnePlusNLayoutHelper
。FixAreaLayoutHelper
:fix 類型的佈局,子節點不隨頁面滾動而滾動。主要實現layoutViews()
、beforeLayout()
、afterLayout()
等方法,可參考FixLayoutHelper
。