發(fā)布時(shí)間:2024-01-23 11:49:04 瀏覽量:208次
電商圖
Github - alibaba - vlayout
目錄
在講解 V - Layout 前,我們先來搞懂一個(gè)問題:為什么要使用 V - Layout
但是,很多時(shí)候我們需要在一個(gè)長列表下做多種類型的布局來分配各種元素,,特別是電商平臺首頁等頁面,布局元素結(jié)構(gòu)更加復(fù)雜多樣。如下圖:
電商圖
此時(shí)的解決方案有所變化:不采用子View的復(fù)用,只采用一個(gè)主要的復(fù)用容器(如ListView 或 RecyclerView+LinearLayoutManager),然后在其中使用嵌套方式直接用各個(gè)組件進(jìn)行拼接,減少了復(fù)用的能力
這種做法還是會損失Android應(yīng)用的性能。
基于 RecyclerView & LayoutManager擴(kuò)展 目前已在Github開源:Github - alibaba - vlayout
效果圖
V - Layout 目前已在手機(jī)天貓 & 淘寶 Android 版內(nèi)廣泛使用
實(shí)際應(yīng)用效果圖
V - Layout的本質(zhì)原理是:通過自定義一個(gè)VirtualLayoutManager(繼承自 LayoutManager),用于管理一系列LayoutHelper,將具體的布局能力交給LayoutHelper來完成,從而 快速實(shí)現(xiàn)組合布局 的需求。
每個(gè) LayoutHelper負(fù)責(zé) 頁面某一個(gè)范圍內(nèi)的布局 V - Layout默認(rèn)實(shí)現(xiàn)了10種默認(rèn)布局:(對應(yīng)同名的LayoutHelper)
布局類型
示意圖
布局類型
下面會進(jìn)行詳細(xì)介紹。
介紹完類之后,我將詳細(xì)分析 V - Layout的工作流程。
工作流程
初始化流程與使用普通的 RecyclerView + LayoutManager 初始化流程基本一致:Vlayout的使用者
初始化流程
示意圖
布局流程
下面用一張圖總結(jié) V - Layout 的原理 & 工作流程
原理 & 工作流程
在講完原理后,接下來我將如何使用 V - Layout。
使用步驟
下面我將對每個(gè)步驟進(jìn)行詳細(xì)說明。
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// 創(chuàng)建RecyclerView對象
VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
// 創(chuàng)建VirtualLayoutManager對象
// 同時(shí)內(nèi)部會創(chuàng)建一個(gè)LayoutHelperFinder對象,用來后續(xù)的LayoutHelper查找
recyclerView.setLayoutManager(layoutManager);
// 將VirtualLayoutManager綁定到recyclerView
如果一屏內(nèi)相同類型的 View 個(gè)數(shù)比較多,需要設(shè)置一個(gè)合適的大小,防止來回滾動(dòng)時(shí)重新創(chuàng)建 View)
// 設(shè)置組件復(fù)用回收池
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
recyclerView.setRecycledViewPool(viewPool);
viewPool.setMaxRecycledViews(0, 10);
設(shè)置 V - Layout的Adapter有兩種方式:
方式1:繼承 自 DelegateAdapter
繼承自VirtualLayoutAdapter
特別注意:雖不可直接綁定LayoutHelper,但是它內(nèi)部有一個(gè)繼承自RecyclerView.Adapter的內(nèi)部類Adapter可以綁定LayoutHelper; 即通過一個(gè)List把綁定好的Adapter打包起來,再放去DelegateAdapter,這樣就可以實(shí)現(xiàn)組合使用不同的布局
寫法與復(fù)寫系統(tǒng)自帶的Adapter非常類似:只比系統(tǒng)自帶的RecyclerAdapter需要多重載onCreateLayoutHelper方法,其余類似 關(guān)于Android系統(tǒng)自帶的RecyclerAdapter的使用具體請看我寫的文章Android開發(fā):ListView、AdapterView、RecyclerView全面解析
public class MyAdapter extends DelegateAdapter.Adapter<MyAdapter.MainViewHolder> {
// 比系統(tǒng)自帶的RecyclerAdapter需要多重載onCreateLayoutHelper()
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
... // 其余寫法與復(fù)寫系統(tǒng)自帶的Adapter相同
}
方式2:繼承 自 VirtualLayoutAdapter
public class MyAdapter extends VirtualLayoutAdapter {
...// 自定義Adapter邏輯
}
布局類型
示意圖
/**
設(shè)置線性布局
*/
LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();
// 創(chuàng)建對應(yīng)的LayoutHelper對象
// 所有布局的公共屬性(屬性會在下面詳細(xì)說明)
linearLayoutHelper.setItemCount(4);// 設(shè)置布局里Item個(gè)數(shù)
linearLayoutHelper.setPadding(10,10,10,10);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
linearLayoutHelper.setMargin(10,10,10,10);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
linearLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
linearLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// linearLayoutHelper特有屬性
linearLayoutHelper.setDividerHeight(1); // 設(shè)置每行Item的距離
a. setItemCount屬性
如設(shè)置的Item總數(shù)如與Adapter的getItemCount()方法返回的數(shù)量不同,會取決于后者
示意圖
// 接口示意
public void setItemCount(int Count)
// 具體使用
linearLayoutHelper.setItemCount(4);
b. Adding & Margin屬性
// 接口示意
public void setPadding(int leftPadding, int topPadding, int rightPadding, int bottomPadding)
public void setMargin(int leftMargin, int topMargin, int rightMargin, int bottomMargin)
// 具體使用
linearLayoutHelper.setPadding(10,10,10,10);
// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
linearLayoutHelper.setMargin(10,10,10,10);
// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
c. bgColor屬性
// 接口示意
public void setBgColor(int bgColor)
// 具體使用
linearLayoutHelper.setBgColor(Color.YELLOW);
d. aspectRatio屬性
示意圖
// 接口示意
public void setAspectRatio(float aspectRatio);
// LayoutHelper定義的aspectRatio
((VirutalLayoutManager.LayoutParams) layoutParams).mAspectRatio
// 視圖的LayoutParams定義的aspectRatio
// 在LayoutHelper計(jì)算出視圖寬度之后,用來確定視圖高度時(shí)使用的,它會覆蓋通過LayoutHelper的aspectRatio計(jì)算出來的視圖高度,因此具備更高優(yōu)先級。
// 具體使用
linearLayoutHelper.setAspectRatio(6);
a. dividerHeight屬性
設(shè)置的間隔會與RecyclerView的addItemDecoration()添加的間隔疊加
示意圖
// 接口示意
public void setDividerHeight(int dividerHeight)
// 具體使用
linearLayoutHelper.setDividerHeight(1);
示意圖
/**
設(shè)置Grid布局
*/
GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(3);
// 在構(gòu)造函數(shù)設(shè)置每行的網(wǎng)格個(gè)數(shù)
// 公共屬性
gridLayoutHelper.setItemCount(6);// 設(shè)置布局里Item個(gè)數(shù)
gridLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
gridLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
gridLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
gridLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// gridLayoutHelper特有屬性(下面會詳細(xì)說明)
gridLayoutHelper.setWeights(new float[]{40, 30, 30});//設(shè)置每行中 每個(gè)網(wǎng)格寬度 占 每行總寬度 的比例
gridLayoutHelper.setVGap(20);// 控制子元素之間的垂直間距
gridLayoutHelper.setHGap(20);// 控制子元素之間的水平間距
gridLayoutHelper.setAutoExpand(false);//是否自動(dòng)填充空白區(qū)域
gridLayoutHelper.setSpanCount(3);// 設(shè)置每行多少個(gè)網(wǎng)格
// 通過自定義SpanSizeLookup來控制某個(gè)Item的占網(wǎng)格個(gè)數(shù)
gridLayoutHelper.setSpanSizeLookup(new GridLayoutHelper.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (position > 7 ) {
return 3;
// 第7個(gè)位置后,每個(gè)Item占3個(gè)網(wǎng)格
}else {
return 2;
// 第7個(gè)位置前,每個(gè)Item占2個(gè)網(wǎng)格
}
}
});
a. weights屬性
默認(rèn)情況下,每行中每個(gè)網(wǎng)格中的寬度相等 weights屬性是一個(gè)float數(shù)組,每一項(xiàng)代表當(dāng)個(gè)網(wǎng)格占每行總寬度的百分比;總和是100,否則布局會超出容器寬度; 如果布局中有4列,那么weights的長度也應(yīng)該是4;長度大于4,多出的部分不參與寬度計(jì)算;如果小于4,不足的部分默認(rèn)平分剩余的空間。
示意圖
// 接口示意
public void setWeights(float[] weights)
// 具體使用
gridLayoutHelper.setWeights(new float[]{40, 30, 30});
b. vGap、hGap屬性
示意圖
// 接口示意
public void setHGap(int hGap)
public void setVGap(int vGap)
// 具體使用
gridLayoutHelper.setVGap(20);// 控制子元素之間的垂直間距
gridLayoutHelper.setHGap(20);// 控制子元素之間的水平間距
c. spanCount、spanSizeLookup屬性
示意圖
// 接口示意
public void setSpanCount(int spanCount)
public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup)
// 具體使用
gridLayoutHelper.setSpanCount(5);// 設(shè)置每行多少個(gè)網(wǎng)格
// 通過自定義SpanSizeLookup來控制某個(gè)Item的占網(wǎng)格個(gè)數(shù)
gridLayoutHelper.setSpanSizeLookup(new GridLayoutHelper.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (position > 7 ) {
return 3;
// 第7個(gè)位置后,每個(gè)Item占3個(gè)網(wǎng)格
}else {
return 2;
// 第7個(gè)位置前,每個(gè)Item占2個(gè)網(wǎng)格
}
}
});
d. autoExpand屬性
若autoExpand=true,那么視圖的總寬度會填滿可用區(qū)域; 否則會在屏幕上留空白區(qū)域。
示意圖
// 接口示意
public void setAutoExpand(boolean isAutoExpand)
// 具體使用
gridLayoutHelper.setAutoExpand(false);
固定在屏幕某個(gè)位置,且不可拖拽 & 不隨頁面滾動(dòng)而滾動(dòng)。如下圖:(左上角)
固定布局
/**
設(shè)置固定布局
*/
FixLayoutHelper fixLayoutHelper = new FixLayoutHelper(FixLayoutHelper.TOP_LEFT,40,100);
// 參數(shù)說明:
// 參數(shù)1:設(shè)置吸邊時(shí)的基準(zhǔn)位置(alignType) - 有四個(gè)取值:TOP_LEFT(默認(rèn)), TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT
// 參數(shù)2:基準(zhǔn)位置的偏移量x
// 參數(shù)3:基準(zhǔn)位置的偏移量y
// 公共屬性
fixLayoutHelper.setItemCount(1);// 設(shè)置布局里Item個(gè)數(shù)
// 從設(shè)置Item數(shù)目的源碼可以看出,一個(gè)FixLayoutHelper只能設(shè)置一個(gè)
// @Override
// public void setItemCount(int itemCount) {
// if (itemCount > 0) {
// super.setItemCount(1);
// } else {
// super.setItemCount(0);
// }
// }
fixLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
fixLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
fixLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
fixLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// fixLayoutHelper特有屬性
fixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT);// 設(shè)置吸邊時(shí)的基準(zhǔn)位置(alignType)
fixLayoutHelper.setX(30);// 設(shè)置基準(zhǔn)位置的橫向偏移量X
fixLayoutHelper.setY(50);// 設(shè)置基準(zhǔn)位置的縱向偏移量Y
a. AlignType、x、y屬性
示意圖
// 接口示意
public void setAlignType(int alignType)
public void setX(int x)
public void setY(int y)
// 具體使用
fixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT);
fixLayoutHelper.setX(30);
fixLayoutHelper.setY(50);
固定在屏幕某個(gè)位置,且不可拖拽 & 不隨頁面滾動(dòng)而滾動(dòng)(繼承自固定布局(FixLayoutHelper)) 唯一不同的是,可以自由設(shè)置該Item什么時(shí)候顯示(到頂部顯示 / 到底部顯示),可如下圖:(左上角) 需求場景:到頁面底部顯示”一鍵到頂部“的按鈕功能
以下示意圖為:滑動(dòng)到底部,布局才在左上角顯示
滑動(dòng)到底部才在左上角顯示
/**
設(shè)置可選固定布局
*/
ScrollFixLayoutHelper scrollFixLayoutHelper = new ScrollFixLayoutHelper(ScrollFixLayoutHelper.TOP_RIGHT,0,0);
// 參數(shù)說明:
// 參數(shù)1:設(shè)置吸邊時(shí)的基準(zhǔn)位置(alignType) - 有四個(gè)取值:TOP_LEFT(默認(rèn)), TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT
// 參數(shù)2:基準(zhǔn)位置的偏移量x
// 參數(shù)3:基準(zhǔn)位置的偏移量y
// 公共屬性
scrollFixLayoutHelper.setItemCount(1);// 設(shè)置布局里Item個(gè)數(shù)
// 從設(shè)置Item數(shù)目的源碼可以看出,一個(gè)FixLayoutHelper只能設(shè)置一個(gè)
// @Override
// public void setItemCount(int itemCount) {
// if (itemCount > 0) {
// super.setItemCount(1);
// } else {
// super.setItemCount(0);
// }
// }
scrollFixLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
scrollFixLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
scrollFixLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
scrollFixLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// fixLayoutHelper特有屬性
scrollFixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT);// 設(shè)置吸邊時(shí)的基準(zhǔn)位置(alignType)
scrollFixLayoutHelper.setX(30);// 設(shè)置基準(zhǔn)位置的橫向偏移量X
scrollFixLayoutHelper.setY(50);// 設(shè)置基準(zhǔn)位置的縱向偏移量Y
scrollFixLayoutHelper.setShowType(ScrollFixLayoutHelper.SHOW_ON_ENTER);// 設(shè)置Item的顯示模式
a. AlignType、x、y屬性
示意圖
// 接口示意
public void setAlignType(int alignType)
public void setX(int x)
public void setY(int y)
// 具體使用
ScrollFixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT);
ScrollFixLayoutHelper.setX(30);
ScrollFixLayoutHelper.setY(50);
b. ShowType屬性
共有三種顯示模式
SHOW_ALWAYS:永遠(yuǎn)顯示(即效果同固定布局) SHOW_ON_ENTER:默認(rèn)不顯示視圖,當(dāng)頁面滾動(dòng)到該視圖位置時(shí)才顯示; SHOW_ON_LEAVE:默認(rèn)不顯示視圖,當(dāng)頁面滾出該視圖位置時(shí)才顯示
// 接口示意
public void setShowType(int showType)
// 具體使用
scrollFixLayoutHelper.setShowType(ScrollFixLayoutHelper.SHOW_ON_ENTER);
可隨意拖動(dòng),但最終會被吸邊到兩側(cè) 不隨頁面滾動(dòng)而移動(dòng)
示意圖
/**
設(shè)置浮動(dòng)布局
*/
FloatLayoutHelper floatLayoutHelper = new FloatLayoutHelper();
// 創(chuàng)建FloatLayoutHelper對象
// 公共屬性
floatLayoutHelper.setItemCount(1);// 設(shè)置布局里Item個(gè)數(shù)
// 從設(shè)置Item數(shù)目的源碼可以看出,一個(gè)FixLayoutHelper只能設(shè)置一個(gè)
// @Override
// public void setItemCount(int itemCount) {
// if (itemCount > 0) {
// super.setItemCount(1);
// } else {
// super.setItemCount(0);
// }
// }
floatLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
floatLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
floatLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
floatLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// floatLayoutHelper特有屬性
floatLayoutHelper.setDefaultLocation(300,300);// 設(shè)置布局里Item的初始位置
可理解為只有一行的線性布局
示意圖
/**
設(shè)置欄格布局
*/
ColumnLayoutHelper columnLayoutHelper = new ColumnLayoutHelper();
// 創(chuàng)建對象
// 公共屬性
columnLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個(gè)數(shù)
columnLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
columnLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
columnLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
columnLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// columnLayoutHelper特有屬性
columnLayoutHelper.setWeights(new float[]{30, 40, 30});// 設(shè)置該行每個(gè)Item占該行總寬度的比例
// 同上面Weigths屬性講解
示意圖
/**
設(shè)置通欄布局
*/
SingleLayoutHelper singleLayoutHelper = new SingleLayoutHelper();
// 公共屬性
singleLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個(gè)數(shù)
singleLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
singleLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
singleLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
singleLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
示意圖1
示意圖2
/**
設(shè)置1拖N布局
*/
OnePlusNLayoutHelper onePlusNLayoutHelper = new OnePlusNLayoutHelper(5);
// 在構(gòu)造函數(shù)里傳入顯示的Item數(shù)
// 最多是1拖4,即5個(gè)
// 公共屬性
onePlusNLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個(gè)數(shù)
onePlusNLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
onePlusNLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
onePlusNLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
onePlusNLayoutHelper.setAspectRatio(3);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
示意圖
/**
設(shè)置吸邊布局
*/
StickyLayoutHelper stickyLayoutHelper = new StickyLayoutHelper();
// 公共屬性
stickyLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個(gè)數(shù)
stickyLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
stickyLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
stickyLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
stickyLayoutHelper.setAspectRatio(3);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// 特有屬性
stickyLayoutHelper.setStickyStart(true);
// true = 組件吸在頂部
// false = 組件吸在底部
stickyLayoutHelper.setOffset(100);// 設(shè)置吸邊位置的偏移量
Adapter_StickyLayout = new MyAdapter(this, stickyLayoutHelper,1, listItem) {
// 設(shè)置需要展示的數(shù)據(jù)總數(shù),此處設(shè)置是1
// 為了展示效果,通過重寫onBindViewHolder()將布局的第一個(gè)數(shù)據(jù)設(shè)置為Stick
@Override
public void onBindViewHolder(MainViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (position == 0) {
holder.Text.setText("Stick");
}
}
};
adapters.add(Adapter_StickyLayout) ;
// 將當(dāng)前的Adapter加入到Adapter列表里
// 接口示意
public void setStickyStart(boolean stickyStart)
public void setOffset(int offset)
// 具體使用
stickyLayoutHelper.setStickyStart(true);
// true = 組件吸在頂部
// false = 組件吸在底部
stickyLayoutHelper.setOffset(100);// 設(shè)置吸邊位置的偏移量
示意圖
/**
設(shè)置瀑布流布局
*/
StaggeredGridLayoutHelper staggeredGridLayoutHelper = new StaggeredGridLayoutHelper();
// 創(chuàng)建對象
// 公有屬性
staggeredGridLayoutHelper.setItemCount(20);// 設(shè)置布局里Item個(gè)數(shù)
staggeredGridLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
staggeredGridLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
staggeredGridLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
staggeredGridLayoutHelper.setAspectRatio(3);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// 特有屬性
staggeredGridLayoutHelper.setLane(3);// 設(shè)置控制瀑布流每行的Item數(shù)
staggeredGridLayoutHelper.setHGap(20);// 設(shè)置子元素之間的水平間距
staggeredGridLayoutHelper.setVGap(15);// 設(shè)置子元素之間的垂直間距
除了使用系統(tǒng)提供的默認(rèn)布局 LayoutHelper,開發(fā)者還可以通過自定義LayoutHelper從而實(shí)現(xiàn)自定義布局樣式。有三種方式:
LinearLayoutHelper、GridLayoutHelper都是采用該方法實(shí)現(xiàn)
OnePlusNLayoutHelper采用該方法實(shí)現(xiàn)
FixLayoutHelper采用該方法實(shí)現(xiàn)
此處的做法會因步驟3中Adapter的設(shè)置而有所不同
<-- Adapter繼承 自 DelegateAdapter -->
// 步驟1:設(shè)置Adapter列表(同時(shí)也是設(shè)置LayoutHelper列表)
List<DelegateAdapter.Adapter> adapters = new LinkedList<>();
// 步驟2:創(chuàng)建自定義的Adapter對象 & 綁定數(shù)據(jù) & 綁定上述對應(yīng)的LayoutHelper
// 綁定你需要展示的布局LayoutHelper即可,此處僅展示兩個(gè)。
MyAdapter Adapter_linearLayout = new MyAdapter(this, linearLayoutHelper,ListItem);
// ListItem是需要綁定的數(shù)據(jù)(其實(shí)取決于你的Adapter如何定義)
MyAdapter Adapter_gridLayoutHelper = new MyAdapter(this, gridLayoutHelper,ListItem);
// 步驟3:將創(chuàng)建的Adapter對象放入到DelegateAdapter.Adapter列表里
adapters.add(Adapter_linearLayout ) ;
adapters.add(Adapter_gridLayoutHelper ) ;
// 步驟4:創(chuàng)建DelegateAdapter對象 & 將layoutManager綁定到DelegateAdapter
DelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager);
// 步驟5:將DelegateAdapter.Adapter列表綁定到DelegateAdapter
delegateAdapter.setAdapters(adapters);
// 步驟6:將delegateAdapter綁定到recyclerView
recyclerView.setAdapter(delegateAdapter);
<-- Adapter繼承 自 VirtualLayoutAdapter -->
// 步驟1:設(shè)置LayoutHelper列表
List<LayoutHelper> helpers = new LinkedList<>();
// 步驟2:綁定上述對應(yīng)的LayoutHelper
helpers.add(Adapter_linearLayout );
helpers.add(Adapter_gridLayoutHelper ) ;
// 步驟3:創(chuàng)建自定義的MyAdapter對象 & 綁定layoutManager
MyAdapter myAdapter = new MyAdapter(layoutManager);
// 步驟4:將 layoutHelper 列表傳遞給 adapter
myAdapter.setLayoutHelpers(helpers);
// 步驟5:將adapter綁定到recyclerView
recycler.setAdapter(myAdapter);
至此,使用過程講解完畢。
compile ('com.alibaba.android:vlayout:1.0.3@aar') {
transitive = true
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="scut.carson_ho.v_layoutusage.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="horizontal" />
</RelativeLayout>
item.xml
此處定義的 Item 布局是常用的 上字下圖
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="New Text"
android:id="@+id/Item" />
<ImageView
android:layout_alignParentRight="true"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/Image"/>
</LinearLayout>
此處主要以該方式進(jìn)行演示
MyAdapter.java
public class MyAdapter extends DelegateAdapter.Adapter<MyAdapter.MainViewHolder> {
// 使用DelegateAdapter首先就是要自定義一個(gè)它的內(nèi)部類Adapter,讓LayoutHelper和需要綁定的數(shù)據(jù)傳進(jìn)去
// 此處的Adapter和普通RecyclerView定義的Adapter只相差了一個(gè)onCreateLayoutHelper()方法,其他的都是一樣的做法.
private ArrayList<HashMap<String, Object>> listItem;
// 用于存放數(shù)據(jù)列表
private Context context;
private LayoutHelper layoutHelper;
private RecyclerView.LayoutParams layoutParams;
private int count = 0;
private MyItemClickListener myItemClickListener;
// 用于設(shè)置Item點(diǎn)擊事件
//構(gòu)造函數(shù)(傳入每個(gè)的數(shù)據(jù)列表 & 展示的Item數(shù)量)
public MyAdapter(Context context, LayoutHelper layoutHelper, int count, ArrayList<HashMap<String, Object>> listItem) {
this(context, layoutHelper, count, new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300), listItem);
}
public MyAdapter(Context context, LayoutHelper layoutHelper, int count, @NonNull RecyclerView.LayoutParams layoutParams, ArrayList<HashMap<String, Object>> listItem) {
this.context = context;
this.layoutHelper = layoutHelper;
this.count = count;
this.layoutParams = layoutParams;
this.listItem = listItem;
}
// 把ViewHolder綁定Item的布局
@Override
public MainViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MainViewHolder(LayoutInflater.from(context).inflate(R.layout.item, parent, false));
}
// 此處的Adapter和普通RecyclerView定義的Adapter只相差了一個(gè)onCreateLayoutHelper()方法
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
// 綁定Item的數(shù)據(jù)
@Override
public void onBindViewHolder(MainViewHolder holder, int position) {
holder.Text.setText((String) listItem.get(position).get("ItemTitle"));
holder.image.setImageResource((Integer) listItem.get(position).get("ItemImage"));
}
// 返回Item數(shù)目
@Override
public int getItemCount() {
return count;
}
// 設(shè)置Item的點(diǎn)擊事件
// 綁定MainActivity傳進(jìn)來的點(diǎn)擊監(jiān)聽器
public void setOnItemClickListener(MyItemClickListener listener) {
myItemClickListener = listener;
}
//定義Viewholder
class MainViewHolder extends RecyclerView.ViewHolder {
public TextView Text;
public ImageView image;
public MainViewHolder(View root) {
super(root);
// 綁定視圖
Text = (TextView) root.findViewById(R.id.Item);
image = (ImageView) root.findViewById(R.id.Image);
root.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (myItemClickListener != null)
myItemClickListener.onItemClick(v, getPosition());
}
}
//監(jiān)聽到點(diǎn)擊就回調(diào)MainActivity的onItemClick函數(shù)
);
}
public TextView getText() {
return Text;
}
}
}
步驟5:創(chuàng)建RecyclerView & VirtualLayoutManager 對象并進(jìn)行綁定 步驟6:設(shè)置回收復(fù)用池大小 步驟7:設(shè)置需要存放的數(shù)據(jù) 步驟8:根據(jù)數(shù)據(jù)列表,創(chuàng)建對應(yīng)的LayoutHelper 步驟9:將生成的LayoutHelper 交給Adapter,并綁定到RecyclerView 對象
詳細(xì)請看注釋
MainActivity.java
public class MainActivity extends AppCompatActivity implements MyItemClickListener {
RecyclerView recyclerView;
MyAdapter Adapter_linearLayout,Adapter_GridLayout,Adapter_FixLayout,Adapter_ScrollFixLayout
,Adapter_FloatLayout,Adapter_ColumnLayout,Adapter_SingleLayout,Adapter_onePlusNLayout,
Adapter_StickyLayout,Adapter_StaggeredGridLayout;
private ArrayList<HashMap<String, Object>> listItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 步驟1:創(chuàng)建RecyclerView & VirtualLayoutManager 對象并進(jìn)行綁定
* */
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// 創(chuàng)建RecyclerView對象
VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
// 創(chuàng)建VirtualLayoutManager對象
// 同時(shí)內(nèi)部會創(chuàng)建一個(gè)LayoutHelperFinder對象,用來后續(xù)的LayoutHelper查找
recyclerView.setLayoutManager(layoutManager);
// 將VirtualLayoutManager綁定到recyclerView
/**
* 步驟2:設(shè)置組件復(fù)用回收池
* */
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
recyclerView.setRecycledViewPool(viewPool);
viewPool.setMaxRecycledViews(0, 10);
/**
* 步驟3:設(shè)置需要存放的數(shù)據(jù)
* */
listItem = new ArrayList<HashMap<String, Object>>();
for (int i = 0; i < 100; i++) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("ItemTitle", "第" + i + "行");
map.put("ItemImage", R.mipmap.ic_launcher);
listItem.add(map);
}
/**
* 步驟4:根據(jù)數(shù)據(jù)列表,創(chuàng)建對應(yīng)的LayoutHelper
* */
// 為了展示效果,此處將上面介紹的所有布局都顯示出來
/**
設(shè)置線性布局
*/
LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();
// 創(chuàng)建對應(yīng)的LayoutHelper對象
// 公共屬性
linearLayoutHelper.setItemCount(4);// 設(shè)置布局里Item個(gè)數(shù)
linearLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離
linearLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離
// linearLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色
linearLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比
// linearLayoutHelper特有屬性
linearLayoutHelper.setDividerHeight(10);
// 設(shè)置間隔高度
// 設(shè)置的間隔會與RecyclerView的addItemDecoration()添加的間隔疊加.
linearLayoutHelper.setMarginBottom(100);
// 設(shè)置布局底部與下個(gè)布局的間隔
// 創(chuàng)建自定義的Adapter對象 & 綁定數(shù)據(jù) & 綁定對應(yīng)的LayoutHelper進(jìn)行布局繪制
Adapter_linearLayout = new MyAdapter(this, linearLayoutHelper, 4, listItem) {
// 參數(shù)2:綁定綁定對應(yīng)的LayoutHelper
// 參數(shù)3:傳入該布局需要顯示的數(shù)據(jù)個(gè)數(shù)
// 參數(shù)4:傳入需要綁定的數(shù)據(jù)
// 通過重寫onBindViewHolder()設(shè)置更豐富的布局效果
@Override
public void onBindViewHolder(MainViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
// 為了展示效果,將布局的第一個(gè)數(shù)據(jù)設(shè)置為linearLayout
if (position == 0) {
holder.Text.setText("Linear");
}
//為了展示效果,將布局里不同位置的Item進(jìn)行背景顏色設(shè)置
if (position < 2) {
holder.itemView.setBackgroundColor(0x66cc0000 + (position - 6) * 128);
} else if (position % 2 == 0) {
holder.itemView.setBackgroundColor(0xaa22ff22);
} else {
holder.itemView.setBackgroundColor(0xccff22ff);
}
}
};
Adapter_linearLayout.setOnItemClickListener(this);
// 設(shè)置每個(gè)Item的點(diǎn)擊事件
....// 還有其他布局,由于代碼量就較多就不貼出來了。
/**
*步驟5:將生成的LayoutHelper 交給Adapter,并綁定到RecyclerView 對象
**/
// 1. 設(shè)置Adapter列表(同時(shí)也是設(shè)置LayoutHelper列表)
List<DelegateAdapter.Adapter> adapters = new LinkedList<>();
// 2. 將上述創(chuàng)建的Adapter對象放入到DelegateAdapter.Adapter列表里
adapters.add(Adapter_linearLayout) ;
adapters.add(Adapter_StickyLayout) ;
adapters.add(Adapter_ScrollFixLayout) ;
adapters.add(Adapter_GridLayout) ;
adapters.add(Adapter_FixLayout) ;
adapters.add(Adapter_FloatLayout) ;
adapters.add(Adapter_ColumnLayout) ;
adapters.add(Adapter_SingleLayout) ;
adapters.add(Adapter_onePlusNLayout) ;
adapters.add(Adapter_StaggeredGridLayout) ;
// 3. 創(chuàng)建DelegateAdapter對象 & 將layoutManager綁定到DelegateAdapter
DelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager);
// 4. 將DelegateAdapter.Adapter列表綁定到DelegateAdapter
delegateAdapter.setAdapters(adapters);
// 5. 將delegateAdapter綁定到recyclerView
recyclerView.setAdapter(delegateAdapter);
/**
*步驟6:Item之間的間隔
**/
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.set(5, 5, 5, 5);
}
});
}
/**
*步驟7:實(shí)現(xiàn)Item點(diǎn)擊事件
**/
// 點(diǎn)擊事件的回調(diào)函數(shù)
@Override
public void onItemClick(View view, int postion) {
System.out.println("點(diǎn)擊了第"+postion+"行");
Toast.makeText(this, (String) listItem.get(postion).get("ItemTitle"), Toast.LENGTH_SHORT).show();
}
}
需要的朋友可以私信【學(xué)習(xí)】我分享給你,希望里面的資料可以給你們一個(gè)更好的學(xué)習(xí)參考。
好了,以上便是今天的分享,希望為各位后續(xù)的學(xué)習(xí)提供方便。覺得內(nèi)容不錯(cuò),也歡迎多多轉(zhuǎn)發(fā)分享給身邊的朋友哈。
熱門資訊
1. iPhone6的UI設(shè)計(jì)尺寸規(guī)范,原來如此重要!
想要了解iPhone6界面設(shè)計(jì)的尺寸規(guī)范嗎?這里為您詳細(xì)介紹iPhone6的UI設(shè)計(jì)尺寸規(guī)范,包括界面尺寸、圖標(biāo)尺寸、可點(diǎn)擊高度規(guī)范、搜索欄高度規(guī)范以及界面元素之間的距離規(guī)范。
2. 12個(gè)絕佳的UI設(shè)計(jì)網(wǎng)站,助力你的創(chuàng)作之旅!
將為大家介紹12個(gè)絕佳的UI設(shè)計(jì)網(wǎng)站,這些網(wǎng)站不僅可以為你提供靈感,還可以幫助你學(xué)習(xí)新的技巧,助力你的創(chuàng)意之旅!dribbbleDribbble 是一個(gè)面向設(shè)計(jì)師的...
3. 移動(dòng)端UI設(shè)計(jì)中常見的5種APP界面類型,你get到了嗎?
通過介紹移動(dòng)端UI設(shè)計(jì)中的閃屏頁、引導(dǎo)頁、浮層引導(dǎo)頁、空白頁和首頁等5種APP界面類型,幫助大家更好地了解UI設(shè)計(jì)的基本知識
4. 10個(gè)免費(fèi)學(xué)習(xí)UI設(shè)計(jì)的網(wǎng)站 提升你的設(shè)計(jì)能力
怎樣可以提升你的UI設(shè)計(jì)能力!第一個(gè):站酷站酷想必是設(shè)計(jì)師都知道的一個(gè)網(wǎng)站,里面不止有UI設(shè)計(jì)的資源,還有其他設(shè)計(jì)的,不如:平面設(shè)計(jì)、網(wǎng)頁設(shè)計(jì)、字體...
5. 移動(dòng)端列表頁和表單頁設(shè)計(jì)秘訣:讓你的APP點(diǎn)擊率翻倍
在移動(dòng)端設(shè)計(jì)中,列表頁和表單頁是不可或缺的部分。一個(gè)好的列表頁和表單頁設(shè)計(jì)能夠讓用戶輕松地獲取信息并產(chǎn)生點(diǎn)擊欲望,從而提高點(diǎn)擊率。本文將為你...
6. 推薦10本適合UI設(shè)計(jì)師看的書籍,輕松掌握技能!
對于想要提高自己的設(shè)計(jì)能力和創(chuàng)造力的小白和UI設(shè)計(jì)師來說,這本書是一個(gè)很好的選擇。4.《設(shè)計(jì)的覺醒》(IKKO TANAKA)推薦理由: 這本書是日本現(xiàn)代平面...
7. 零基礎(chǔ)學(xué)UI設(shè)計(jì)要多久?培訓(xùn)完能拿多少工資?
探索零基礎(chǔ)UI設(shè)計(jì)培訓(xùn)的時(shí)長與薪資前景。了解數(shù)字藝術(shù)教育領(lǐng)域的專業(yè)課程,以及培訓(xùn)后的職業(yè)發(fā)展機(jī)會。
8. 物聯(lián)網(wǎng)APP UI設(shè)計(jì):創(chuàng)造智能硬件領(lǐng)域的沉浸式體驗(yàn)
ui設(shè)計(jì)應(yīng)該讓用戶一目了然,能夠快速找到所需的信息和功能。在設(shè)計(jì)過程中,應(yīng)盡量使用簡潔的圖標(biāo)、文字和色彩,避免過多的視覺干擾。符合用戶習(xí)慣:ui設(shè)...
9. 武漢UI設(shè)計(jì)培訓(xùn)班費(fèi)用怎么樣?想學(xué)UI設(shè)計(jì)要多少錢?
想了解武漢UI設(shè)計(jì)培訓(xùn)班的費(fèi)用是多少嗎?不知道學(xué)UI設(shè)計(jì)要花多少錢?不妨看看這篇文章,了解UI設(shè)計(jì)培訓(xùn)班的學(xué)費(fèi)價(jià)格以及學(xué)習(xí)內(nèi)容。
10. 設(shè)計(jì)中的色彩心理學(xué):淺析中西方色彩的歷史演變與設(shè)計(jì)應(yīng)用
摘要:本文探討了色彩的歷史演變和設(shè)計(jì)應(yīng)用。通過對色彩在早期文明社會中的實(shí)用運(yùn)用、不同文化背景下色彩觀念的差異、色彩在設(shè)計(jì)中的重要性以及新興技...
最新文章
同學(xué)您好!