先來(lái)看看下面這個(gè)頁(yè)面的實(shí)現(xiàn):
按照我們平時(shí)的習(xí)慣凯旋,最后的布局文件如下:
<ScrollView>
<LinearLayout>
<ImageView> <頂部圖片>
<LinearLayout><View/><TextView/><LinearLayout> <我的服務(wù)標(biāo)題欄>
<GridView /> <我的服務(wù)功能塊>
<LinearLayout><View/><TextView/><LinearLayout> <我的功能標(biāo)題欄>
<GridView /> <我的功能功能塊>
<LinearLayout>
<ScrollView/>
可以看出,布局很復(fù)雜。如果在想加一個(gè)“我的售后”模塊呢至非,就需要找到相應(yīng)的布局代碼钠署,在相應(yīng)的位置加上布局代碼,這樣很麻煩荒椭,不利于擴(kuò)展...
下面我們來(lái)看看阿里巴巴開(kāi)源的vlayout
對(duì)于上面的頁(yè)面我們來(lái)使用VLayout
來(lái)進(jìn)行實(shí)現(xiàn)谐鼎,我們先看看布局代碼:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rv_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
整個(gè)頁(yè)面的布局,就只有一個(gè)RecyclerView
控件趣惠,簡(jiǎn)單吧...
它的功能實(shí)現(xiàn)狸棍,有兩種寫法,首先我們來(lái)看看比較通用點(diǎn)的實(shí)現(xiàn)味悄,它的思路大概就是:為每個(gè)模塊建立一個(gè)Adapter
草戈,然后將這些Adapter
放入一個(gè)總集合中,最后把這個(gè)集合設(shè)置給RecyclerView
侍瑟。
上面的頁(yè)面唐片,我們可以分為三個(gè)模塊:頂部圖片,標(biāo)題欄涨颜,功能塊费韭。這樣對(duì)應(yīng)的也就有三個(gè)Adapter
,依次如下:
//頂部圖片BannerAdapter
public class BannerAdapter extends DelegateAdapter.Adapter<BannerAdapter.ViewHolder> {
private Context context;
private List<Integer> urls;
private LayoutHelper layoutHelper;
public BannerAdapter(Context context, List<Integer> urls, LayoutHelper layoutHelper){
this.context = context;
this.urls = urls;
this.layoutHelper = layoutHelper;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_banner, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Glide.with(context).load(urls.get(position)).into(holder.imageView);
}
@Override
public int getItemCount() {
return urls.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.iv_banner);
}
}
}
//標(biāo)題欄DividerAdapter
public class DividerAdapter extends DelegateAdapter.Adapter<DividerAdapter.DividerViewHolder> {
private Context context;
private List<String> itemBeanList;
private LayoutHelper layoutHelper;
public DividerAdapter(Context context, List<String> itemBeanList, LayoutHelper layoutHelper){
this.context = context;
this.itemBeanList = itemBeanList;
this.layoutHelper = layoutHelper;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
@Override
public DividerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new DividerViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_divider, parent, false));
}
@Override
public void onBindViewHolder(DividerViewHolder holder, int position) {
holder.tvName.setText(itemBeanList.get(position));
}
@Override
public int getItemCount() {
return itemBeanList.size();
}
public class DividerViewHolder extends RecyclerView.ViewHolder{
private TextView tvName;
public DividerViewHolder(View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
//功能塊ContentAdapter
public class ContentAdapter extends DelegateAdapter.Adapter<ContentAdapter.ContentViewHolder> {
private Context context;
private List<ItemBean> itemBeanList;
private LayoutHelper layoutHelper;
public ContentAdapter(Context context, List<ItemBean> itemBeanList, LayoutHelper layoutHelper){
this.context = context;
this.itemBeanList = itemBeanList;
this.layoutHelper = layoutHelper;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
@Override
public ContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ContentViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_content, parent, false));
}
@Override
public void onBindViewHolder(ContentViewHolder holder, int position) {
Glide.with(context).load(Integer.parseInt(itemBeanList.get(position).getImgUrl())).into(holder.icon);
holder.tvName.setText(itemBeanList.get(position).getName());
}
@Override
public int getItemCount() {
return itemBeanList.size();
}
public class ContentViewHolder extends RecyclerView.ViewHolder{
private ImageView icon;
private TextView tvName;
public ContentViewHolder(View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.iv_icon);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
這樣各個(gè)模塊的適配器就寫完了,下面就是使用了...
VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);//建立我們的委托LayoutManger
rvLayout.setLayoutManager(layoutManager);
/**
* 目前的LayoutHelper有以下幾種:
*
* LinearLayoutHelper: 線性布局
* GridLayoutHelper: Grid布局庭瑰, 支持橫向的colspan
* FixLayoutHelper: 固定布局星持,始終在屏幕固定位置顯示
* ScrollFixLayoutHelper: 固定布局,但之后當(dāng)頁(yè)面滑動(dòng)到該圖片區(qū)域才顯示, 可以用來(lái)做返回頂部或其他書(shū)簽等
* FloatLayoutHelper: 浮動(dòng)布局弹灭,可以固定顯示在屏幕上督暂,但用戶可以拖拽其位置
* ColumnLayoutHelper: 欄格布局,都布局在一排鲤屡,可以配置不同列之間的寬度比值
* SingleLayoutHelper: 通欄布局损痰,只會(huì)顯示一個(gè)組件View
* OnePlusNLayoutHelper: 一拖N布局,可以配置1-5個(gè)子元素
* StickyLayoutHelper: stikcy布局酒来, 可以配置吸頂或者吸底
* StaggeredGridLayoutHelper: 瀑布流布局,可配置間隔高度/寬度
*/
//頂部圖片
SingleLayoutHelper bannerLayoutHelper = new SingleLayoutHelper();
bannerLayoutHelper.setItemCount(1);//設(shè)置子條目個(gè)數(shù)
List<Integer> imgList = new ArrayList<>();
imgList.add(R.drawable.banner);
adapters.add(new BannerAdapter(this, imgList, bannerLayoutHelper));
//第一個(gè)標(biāo)題欄:我的服務(wù)
LinearLayoutHelper serverLayoutHelper = new LinearLayoutHelper();
serverLayoutHelper.setItemCount(1);
List<String> list = new ArrayList<>();
list.add("我的服務(wù)");
adapters.add(new DividerAdapter(this, list, serverLayoutHelper));
//我的服務(wù)肪凛,功能塊
GridLayoutHelper serverGridLayoutHelper = new GridLayoutHelper(3);
serverGridLayoutHelper.setAutoExpand(false);//是否自動(dòng)擴(kuò)展
serverGridLayoutHelper.setWeights(new float[]{33, 33, 33});//設(shè)置權(quán)重
serverGridLayoutHelper.setItemCount(6);
adapters.add(new ContentAdapter(this, serverList, serverGridLayoutHelper));
//第二個(gè)標(biāo)題欄:我的功能
LinearLayoutHelper functionLayoutHelper = new LinearLayoutHelper();
functionLayoutHelper.setItemCount(1);
layoutHelperList.add(functionLayoutHelper);
List<String> list1 = new ArrayList<>();
list1.add("我的功能");
adapters.add(new DividerAdapter(this, list1, functionLayoutHelper));
//我的功能堰汉,功能塊
GridLayoutHelper functionGridLayoutHelper = new GridLayoutHelper(3);
functionGridLayoutHelper.setAutoExpand(false);
functionGridLayoutHelper.setWeights(new float[]{33, 33, 33});
functionGridLayoutHelper.setItemCount(6);
adapters.add(new ContentAdapter(this, functionList, functionGridLayoutHelper));
DelegateAdapter adapter1 = new DelegateAdapter(layoutManager, false);
adapter1.setAdapters(adapters);//添加不同的子Adapter.
rvLayout.setAdapter(adapter1);
這樣就完成了,對(duì)上面頁(yè)面的實(shí)現(xiàn)伟墙。
如果我想新加一個(gè)功能塊翘鸭,我們只需要針對(duì)這個(gè)功能塊,新建一個(gè)Adapter
戳葵,在將其加入集合adapters
中就可以了就乓,不需要在去更改原來(lái)的代碼了....
我們?cè)趤?lái)看看另一種寫法,它的大概思路就是:為每個(gè)模塊設(shè)置一個(gè)LayoutHelper
,然后將其放入LayoutHelper集合中
生蚁,在將此集合設(shè)置給VirtualLayoutManager
,最后在Adapter
中進(jìn)行具體的處理噩翠。具體代碼如下:
VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
rvLayout.setLayoutManager(layoutManager);
getData();//獲取數(shù)據(jù)
/**
* 目前的LayoutHelper有以下幾種:
* LinearLayoutHelper: 線性布局
* GridLayoutHelper: Grid布局, 支持橫向的colspan
* FixLayoutHelper: 固定布局邦投,始終在屏幕固定位置顯示
* ScrollFixLayoutHelper: 固定布局伤锚,但之后當(dāng)頁(yè)面滑動(dòng)到該圖片區(qū)域才顯示, 可以用來(lái)做返回頂部或其他書(shū)簽等
* FloatLayoutHelper: 浮動(dòng)布局,可以固定顯示在屏幕上志衣,但用戶可以拖拽其位置
* ColumnLayoutHelper: 欄格布局屯援,都布局在一排,可以配置不同列之間的寬度比值
* SingleLayoutHelper: 通欄布局念脯,只會(huì)顯示一個(gè)組件View
* OnePlusNLayoutHelper: 一拖N布局狞洋,可以配置1-5個(gè)子元素
* StickyLayoutHelper: stikcy布局, 可以配置吸頂或者吸底
* StaggeredGridLayoutHelper: 瀑布流布局绿店,可配置間隔高度/寬度
*/
List<LayoutHelper> layoutHelperList = new ArrayList<>();
//頂部圖片
SingleLayoutHelper bannerLayoutHelper = new SingleLayoutHelper();
bannerLayoutHelper.setItemCount(1);
layoutHelperList.add(bannerLayoutHelper);
//我的服務(wù)標(biāo)題欄
LinearLayoutHelper serverLayoutHelper = new LinearLayoutHelper();
serverLayoutHelper.setItemCount(1);
layoutHelperList.add(serverLayoutHelper);
//我的服務(wù)
GridLayoutHelper serverGridLayoutHelper = new GridLayoutHelper(3);
serverGridLayoutHelper.setAutoExpand(false);
serverGridLayoutHelper.setWeights(new float[]{33, 33, 33});
serverGridLayoutHelper.setItemCount(6);
layoutHelperList.add(serverGridLayoutHelper);
//我的功能標(biāo)題欄
LinearLayoutHelper functionLayoutHelper = new LinearLayoutHelper();
functionLayoutHelper.setItemCount(1);
layoutHelperList.add(functionLayoutHelper);
//我的功能
GridLayoutHelper functionGridLayoutHelper = new GridLayoutHelper(3);
functionGridLayoutHelper.setAutoExpand(false);
functionGridLayoutHelper.setWeights(new float[]{33, 33, 33});
functionGridLayoutHelper.setItemCount(6);
layoutHelperList.add(functionGridLayoutHelper);
layoutManager.setLayoutHelpers(layoutHelperList);//設(shè)置LayoutHelper集合
VLayoutAdapter adapter = new VLayoutAdapter(layoutManager, this, serverList, functionList);
rvLayout.setAdapter(adapter);
//整體Adapter
public class VLayoutAdapter extends VirtualLayoutAdapter {
private int serverNum;
private int functionNum;
private Context context;
private List<ItemBean> serverList = new ArrayList<>();
private List<ItemBean> functionList = new ArrayList<>();
private final int FLAG_BANNER = 1;//banner
private final int FLAG_DIVIDER = 2;//標(biāo)題欄
private final int FLAG_CONTENT = 3;//功能塊
public VLayoutAdapter(@NonNull VirtualLayoutManager layoutManager, Context context, List<ItemBean> serverList, List<ItemBean> functionList) {
super(layoutManager);
this.serverList = serverList;
this.functionList = functionList;
this.context = context;
serverNum = serverList.size();
functionNum = functionList.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType){
case FLAG_BANNER:
return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_banner, parent, false));
case FLAG_DIVIDER:
return new DividerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_divider, parent, false));
case FLAG_CONTENT:
return new ContentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_content, parent, false));
default:
return null;
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof BannerViewHolder){
Glide.with(context).load(R.drawable.banner).into(((BannerViewHolder) holder).banner);
}else if (holder instanceof DividerViewHolder){
if (position == 1){
((DividerViewHolder) holder).tvName.setText("我的服務(wù)");
((DividerViewHolder) holder).tvName.setTextColor(Color.parseColor("#F9C025"));
}else{
((DividerViewHolder) holder).tvName.setText("我的功能");
((DividerViewHolder) holder).tvName.setTextColor(Color.parseColor("#35A7FF"));
}
}else if (holder instanceof ContentViewHolder){
if (position > 1 && position < 2+serverNum){
((ContentViewHolder) holder).tvName.setText(serverList.get(position-2).getName());
Glide.with(context).load(Integer.parseInt(serverList.get(position-2).getImgUrl())).into(((ContentViewHolder) holder).icon);
}else if (position > 2+serverNum){
((ContentViewHolder) holder).tvName.setText(functionList.get(position-(2+serverNum+1)).getName());
Glide.with(context).load(Integer.parseInt(functionList.get(position-(2+serverNum+1)).getImgUrl())).into(((ContentViewHolder) holder).icon);
}
}
}
@Override
public int getItemCount() {//返回總條目數(shù)
int totalCount = 0;
List<LayoutHelper> helpers = getLayoutHelpers();//獲取全部的LayoutHelper
if (helpers == null ) {
return 0;
}
for (int i = 0; i < helpers.size(); i++) {
totalCount += helpers.get(i).getItemCount();//獲取LayoutHelper中的子條目數(shù)
}
return totalCount;
}
@Override
public int getItemViewType(int position) {
if (position == 0){
return FLAG_BANNER;
}else if (position == 1 || position == (2+serverNum)){
return FLAG_DIVIDER;
}else {
return FLAG_CONTENT;
}
}
public class BannerViewHolder extends RecyclerView.ViewHolder{
private ImageView banner;
public BannerViewHolder(View itemView) {
super(itemView);
banner = itemView.findViewById(R.id.iv_banner);
}
}
public class DividerViewHolder extends RecyclerView.ViewHolder{
private TextView tvName;
public DividerViewHolder(View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tv_name);
}
}
public class ContentViewHolder extends RecyclerView.ViewHolder{
private ImageView icon;
private TextView tvName;
public ContentViewHolder(View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.iv_icon);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
從上面的adapter代碼中可以看出吉懊,如果我新加一個(gè)功能模塊,那么就得新加一個(gè)標(biāo)識(shí)類型惯吕,在onBindViewHolder
中就得多加一條if..else判斷惕它;這樣的話新增功能越多,判定就加的越多废登,對(duì)于維護(hù)不利淹魄;所以這種寫法雖然簡(jiǎn)單,但是不適合功能模塊比較多的頁(yè)面堡距。