概述
在android平時開發中,經常會碰到同一個頁面中有多個list的問題,或者需要再一個list中存在靜態佈局需要與list一起滾動的的需求。
針對這些情況,筆者嘗試過多種方法,如:scrollView嵌套recyclerView,recyclerView嵌套recyclerView等。(主要工作量是在對分發事件的控制)
最終還是認爲使用單獨的一個recyclerView最爲實用,主要優勢如下:
- 減少嵌套層級
- 減少對各種分發事件的控制
此文用簡單demo記之。
筆者認爲單獨使用一個recyclerView最爲實用,並不是說任何場景都要用這個。如下兩個場景就不推薦使用:
- 很多時候,一個頁面中的內容由多個模塊共同拼湊而成,無法只由一個RecyclerView來寫。這種場景還是需要活學活用,使用最方便、風險最小的方式實現。
- 需要給其中一整塊內容添加動畫。這種情況最方便的解決方式還是通過增加層級實現,如果給每個Item都設置一下,反而顯得得不償失。
Demo
此demo主要以“RecyclerView添加header”爲例來表示如何在recyclerView中實現複雜佈局,要點如下:
- 此demo是gridLayout,因此需要自定義GridLayoutManager,在第一行的時候只展示一列。
- Adapter提前在hedaer的位置放一個FrameLayout,這樣設置header的時候只需要addView就可以。(通過這種方式可以讓adapter更加靈活,header的創建與adapter代碼也可以解耦)
- adapter中onCreateViewHolder和onBindViewHolder中要注意根據itemViewType來區分view的類型,根據不同的view設置。(此demo中,只需判斷是header還是正常item)
代碼
MainActivity.java
public class MainActivity extends AppCompatActivity {
//data
private MainRecyclerViewAdapter adapterMain;
//ui
private RecyclerView rvMain;
private View llHeader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initData();
}
private void initViews() {
rvMain = findViewById(R.id.rv_main);
rvMain.setLayoutManager(new MainRecyclerViewAdapter.GridLayoutManager(this));
llHeader = LayoutInflater.from(this).inflate(R.layout.view_recycler_header_main, null);
}
private void initData() {
//設置測試數據
List<String> listData = new ArrayList<>(300);
for (int i = 0; i < 300; i++) {
listData.add(String.valueOf(i));
}
adapterMain = new MainRecyclerViewAdapter(this, rvMain);
rvMain.setAdapter(adapterMain);
adapterMain.setDataList(listData);
adapterMain.setHeader(llHeader);
}
}
MainRecyclerViewAdapter.java
public class MainRecyclerViewAdapter
extends RecyclerView.Adapter<MainRecyclerViewAdapter.ViewHolder> {
//viewType
private final static int VIEW_TYPE_HEADER = 0;
private final static int VIEW_TYPE_DATA = 1;
//data
private Activity mActivity;
private RecyclerView mRecyclerView;
private List<String> dataList;
//ui
private FrameLayout headerContainer;
public MainRecyclerViewAdapter(Activity activity, RecyclerView recyclerView) {
mActivity = activity;
mRecyclerView = recyclerView;
createHeaderContainer();
}
private void createHeaderContainer() {
headerContainer = new FrameLayout(mActivity);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
headerContainer.setLayoutParams(lp);
}
public void setHeader(View header) {
if (headerContainer == null) {
return;
}
headerContainer.removeAllViews();
headerContainer.addView(header);
}
public void setDataList(List<String> dataList) {
this.dataList = dataList;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView;
switch (viewType) {
case VIEW_TYPE_HEADER:
itemView = headerContainer;
break;
default:
itemView = new TextView(mActivity);
itemView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
break;
}
return new ViewHolder(itemView);
}
@Override public int getItemViewType(int position) {
if (position == 0) {
return VIEW_TYPE_HEADER;
}
return VIEW_TYPE_DATA;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
if (position == 0) {
return;
}
String nowData = dataList.get(position - 1);
((TextView) holder.itemView).setText(nowData);
}
@Override
public int getItemCount() {
if (dataList == null) {
return 1;
}
return dataList.size() + 1;
}
//span count
private final static int HEADER_SPAN_COUNT = 1;
private final static int DATA_SPAN_COUNT = 3;
public static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
}
public static class GridLayoutManager extends androidx.recyclerview.widget.GridLayoutManager {
public GridLayoutManager(Context context) {
super(context, DATA_SPAN_COUNT);
this.setSpanSizeLookup(new SpanSizeLookup() {
@Override public int getSpanSize(int position) {
return position == 0 ? DATA_SPAN_COUNT : HEADER_SPAN_COUNT;
}
});
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="RecyclerView測試"
android:textSize="30sp"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
view_recycler_header_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<Button
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="這是內容1"
/>
</LinearLayout>