1. 程式人生 > >RecyclerView實現混合佈局

RecyclerView實現混合佈局

PS:好長時間不寫部落格了,起初是不知道寫些什麼,後來接觸了到了很多東西,原本看似簡單的東西,背後都隱藏著巨大的祕密,想handler的使用,一般情況下會引起記憶體洩漏問題,想著找到方法結局不就得了嗎,可是誰想查閱資料發現,這個東西沒想到牽扯的這麼深, Activity -> handler -> message -> queue -> UI執行緒作為GC Root引用鏈,看都看懵逼了,趕緊看一些稍微簡單的UI 實現,突發奇想,RecyclerView的混合佈局介面的實現。如下圖

。。。

像這些佈局,可以用listview來實現,也可以RecyclerView來實現,每個佈局檔案都是不一樣的,第一張圖:上面是一行三個圖,下面是一行四個圖。第二張圖一行分左右。作為一個新手來說,估計就有點難以招架了,不過用recyclerview就比較好實現了,只要指定Type,來載入不同的佈局就可以。下面來簡單實現一個簡單點的。有一行兩個資料,有一行一個數據介面。

我們可以看到,這個RecyclerView中有多種item顯示出來,那麼具體怎麼實現呢,其實在RecyclerView中,我們可以重寫方法getItemViewType(),這個方法會傳進一個引數position表示當前是第幾個Item,然後我們可以通過position拿到當前的Item物件,然後判斷這個item物件需要那種檢視,返回一個int型別的檢視標誌,然後在onCreatViewHolder方法中給引入佈局,這樣就能夠實現多種item顯示了,我們先來看一下,一共要實現多少方法,他們分別是什麼,我都加了註釋。
/**
     * 載入檢視
     * */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }
    /**
     * 載入資料
     * */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    }

    /**
     * 返回資料數量
     * */
    @Override
    public int getItemCount() {
        return 0;
    }

    /**
     * 返回資料型別
     * */
    @Override
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }

 我們一般情況下會在上面這些方法中做一些具體操作,所以只要掌握了上面這幾個方法,就完全OK了。

步驟:

  1. item的佈局檔案(xml)
  2. item的bean類(第二個方法寫一個)
  3. 自定義ViewHolder類繼承RecyclerView.ViewHolder
  4. 自定義adapter繼承RecyclerView.Adapter<RecyclerView.ViewHolder>
    1. getItemViewType返回type值
    2. onCreateViewHolder載入不同的檢視
    3. onBindViewHolder繫結資料
  5. 主檔案中設定recyclerview的佈局樣式,賦值除錯

 1:Item  xml佈局檔案和Bean類,ViewHolder建立。

注:bean因demo簡潔,並沒有用到bean類。一共兩個佈局,這裡只給出一個,類似寫出即可。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
			  android:layout_width="match_parent"
			  android:layout_height="wrap_content">
	<TextView
			android:layout_width="match_parent"
			android:layout_height="50dp"
			android:gravity="center"
			android:background="@color/colorPrimary"
			android:id="@+id/id_one_tv1"/>
</LinearLayout>

public class TypeViewHolderOne extends RecyclerView.ViewHolder {

    public  TextView textView;

    public TypeViewHolderOne(View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.id_one_tv1);
    }
}

 2:方法講解

注意:一般情況下後天會給移動端返回一串JSON字串,裡面有一些資料是需要自己來專門跳出來的,

方法:

  • 你可以寫多個list來存放不同的資料,但是如果是多個的話,返回的資料就一串字串,你不僅要挑出來,還要存放在多個list裡面,下次下拉重新整理時還要在多個list中累加資料,這樣就有點麻煩了
  • 不挑出來直接就只判斷type,然後根據type去呼叫不同的layout,然後在繫結資料的方法中再次判斷是不是自己想要的ViewHolder,最後賦值顯示。

返回type型別方法

//返回型別,有單列顯示還是雙列顯示
@Override
    public int getItemViewType(int position) {
        return mList.get(position).getType();
}

 

我們重寫了getItemViewType()方法後,就要寫不同的item(佈局檔案),然後在onCreatViewHolder方法引入佈局。這裡的型別就簡單直接寫的1和2。

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    //檢視顯示
    //建立view檢視
    switch (viewType) {
        case 1:
            return new TypeViewHolderOne(layoutInflater.inflate(R.layout.model_view1, parent, false));
        case 2:
            return new TypeViewHolderTwo(layoutInflater.inflate(R.layout.model_view2, parent, false));
    }
    return null;
}

 

我們看到的TypeViewHolderOne(View view);這個方法是自定義的需要繼承RecyclerView.ViewHolder

public class TypeViewHolderOne extends RecyclerView.ViewHolder {
    public  TextView textView;
    public TypeViewHolderOne(View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.id_one_tv1);
    }
}

 

寫到這裡,佈局有了,viewholder有了,資料的判斷型別有了,就差展示了,所以重寫onBindViewHolder方法

/**
 * 方法作用:繫結資料,
 * 方法描述:根據holder對控制元件進行賦值,同時如果有回撥介面,在該方法中寫。
 */
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    //優化   繫結資料
    if(holder instanceof TypeViewHolderOne){//判斷是哪個物件
        TypeViewHolderOne viewHolderOne= (TypeViewHolderOne) holder;
        viewHolderOne.textView.setText(mList.get(position).getName());
    }else if(holder instanceof TypeViewHolderTwo){
        TypeViewHolderTwo viewHolderTwo= (TypeViewHolderTwo) holder;
        viewHolderTwo.textView1.setText(mList.get(position).getName());
        viewHolderTwo.textView2.setText("型別"+mList.get(position).getType());
    }
}

所有預備工作已經做完了,開始賦值。

recyclerViewAdapter = new RecyclerViewAdapter2(this, list);
recyclerView.setAdapter(recyclerViewAdapter);
//本地模擬資料
public void addData() {
    int a=(int)(Math.random()*10);
    TypeBean typeBean;
    for (int i = 0; i < 10; i++) {
        typeBean = new TypeBean();
        typeBean.setName("樣式:" + (i + 1));
        typeBean.setType(1);
        if (i == a) {
            typeBean.setType(2);
        }
        list.add(typeBean);
    }
    recyclerViewAdapter.notifyDataSetChanged();
}

現在還不能執行,因為還沒有給recyclerview指定一個佈局格式,下面是指定了佈局格式,一共兩列,獲取一開始咱們設定的type,如果type=2,則要讓他獨自佔2列,也就是說,他自己一行。

final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
    @Override
    public int getSpanSize(int position) {
        int itemViewType = recyclerView.getAdapter().getItemViewType(position);
        if (itemViewType == 2) {
            return 2;
        }
        return 1;
    }
});

裝飾可寫可不寫

//設定各個item的裝飾,如間距,大小等,可寫可不寫,不寫可以在xml檔案中設定。
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        //super.getItemOffsets(outRect, view, parent, state);
        //拿到Grid管理器
        GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();
        //拿到grid管理器所設定的總列數
        int spanSize = layoutParams.getSpanSize();
        //拿到當前所在列數
        int spanIndex = layoutParams.getSpanIndex();
        //設定頂部間距
        outRect.top = 20;
        if (spanSize != gridLayoutManager.getSpanCount()) {
            if (spanIndex == 1) {
                outRect.left = 10;
            } else {
                outRect.right = 10;
            }
        }
    }
});
recyclerView.setLayoutManager(gridLayoutManager);

 現在執行試試吧

總結:

1:使用RecyclerView必須要寫的就是介面卡要繼承RecyclerView.Adapter<RecyclerView.ViewHolder>,當然這裡面你也可以自定義。

2:載入多個佈局檔案時(item)需要加入Type欄位去判斷是哪一個item。在activity中載入recyclerview時,要加入佈局樣式,比如說,普通的LinearLayoutManager,或者GridLayoutManager,StaggeredGridLayoutManager。不加是不顯示的。