使用RecyclerView解決滑動衝突(RecyclerView添加header)

概述

在android平時開發中,經常會碰到同一個頁面中有多個list的問題,或者需要再一個list中存在靜態佈局需要與list一起滾動的的需求。
針對這些情況,筆者嘗試過多種方法,如:scrollView嵌套recyclerView,recyclerView嵌套recyclerView等。(主要工作量是在對分發事件的控制)

最終還是認爲使用單獨的一個recyclerView最爲實用,主要優勢如下:

  1. 減少嵌套層級
  2. 減少對各種分發事件的控制

此文用簡單demo記之。

筆者認爲單獨使用一個recyclerView最爲實用,並不是說任何場景都要用這個。如下兩個場景就不推薦使用:

  1. 很多時候,一個頁面中的內容由多個模塊共同拼湊而成,無法只由一個RecyclerView來寫。這種場景還是需要活學活用,使用最方便、風險最小的方式實現。
  2. 需要給其中一整塊內容添加動畫。這種情況最方便的解決方式還是通過增加層級實現,如果給每個Item都設置一下,反而顯得得不償失。

Demo

此demo主要以“RecyclerView添加header”爲例來表示如何在recyclerView中實現複雜佈局,要點如下:

  1. 此demo是gridLayout,因此需要自定義GridLayoutManager,在第一行的時候只展示一列。
  2. Adapter提前在hedaer的位置放一個FrameLayout,這樣設置header的時候只需要addView就可以。(通過這種方式可以讓adapter更加靈活,header的創建與adapter代碼也可以解耦)
  3. 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>
發佈了255 篇原創文章 · 獲贊 751 · 訪問量 117萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章