Android中RecyclerView用法,一步一步教你如何使用RecyclerView以及帶你走過編碼中可能會出現的坑~

Fantasy澤發表於2020-08-24

首先,要明白RecyclerView是做什麼的?其次是為什麼要用RecyclerView?這裡牽扯到RecyclerView和ListView的區別,這裡不廢話,大家自行百度即可!

以下示例我用的Android API 29 ,啟用了AndroidX。

第一步,新增依賴

建立一個新的工程,在app/build.gradle中的dependencies閉包新增以下內容:

implementation 'com.android.support:appcompat-v7:29.0.0'

  注意這裡的‘29.0.0’要和你的 compileSdkVersion 版本號一致。版本號是28,就改為28。

別的不需要改,以下是此時的專案目錄以及gradle檔案內容

第二步,建立RecyclerView佈局

在你的佈局檔案中新增RecyclerView,切記要為RecyclerView新增id。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_card"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

 

第三步,為RecyclerView中的item建立一個統一的佈局檔案

在layout下建立一個名為layout_rv_card的佈局檔案,檔名命名要和你的實際業務相匹配方便後期查詢。

 在此佈局檔案中,可以新增任何你想展示的檢視,在這裡我們先建立兩個TextView為大家展示:

<?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="50dp"
    android:gravity="center"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tv_id"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center" />

    <TextView
        android:id="@+id/tv_state"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center" />
</LinearLayout>

  別忘了新增id。

第四步,建立Adapter

  Adapter是連線後端資料和前端顯示的介面卡介面,是資料和UI(View)之間一個重要的紐帶。

  如果之前沒有接觸過,先跟著做,做完之後就會理解了。

  我們在專案目錄下新建一個Java類,取名為CardAdapter。

   然後在CardAdapter中我們建立一個內部類MyViewHolder繼承RecyclerView.ViewHolder。

  為什麼要建立內部類?

  答:就是為了方便而已,建立在外部也是可以,但是如果專案大了之後,類太多不好區分,而且基本上因為佈局的不同ViewHolder也基本不同,不會複用,所以建立在內部即可。

  為什麼要使用ViewHolder?

  答:ViewHolder的主要任務:容納View檢視。前邊我們提到Adapter連線了後端資料和前端顯示,viewHolder的作用就是提供前端的檢視檔案。

接下來,我們在ViewHolder繫結檢視檔案,同在activity中類似,itemView顧名思義即列表中每一項的檢視,每一項都要繫結。

import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

/**
 * @Author: Messi Mei
 * @Date: 2020/8/24 13:46
 * @Email: 709909986@qq.com
 **/
public class CardAdapter {
    
    class MyViewHolder extends RecyclerView.ViewHolder {
        private TextView tvId,tvState;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvId = itemView.findViewById(R.id.tv_id);
            tvState = itemView.findViewById(R.id.tv_state);
        }
    }
}

第五步,完成Adapter

在我們建立的CardAdapter類繼承我們建立的內部類MyViewHolder,並重寫提供的三個方法:

onCreateViewHolder(),onBindViewHolder(),getItemCount()
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

/**
 * @Author: Messi Mei
 * @Date: 2020/8/24 13:46
 * @Email: 709909986@qq.com
 **/
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.MyViewHolder> {

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        private TextView tvId,tvState;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvId = itemView.findViewById(R.id.tv_id);
            tvState = itemView.findViewById(R.id.tv_state);
        }
    }
}

5.1重寫onCreateViewHolder方法,返回我們的內部類MyViewHolder ,此處為將我們的item佈局檔案和adapter繫結。

 @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.layout_rv_card,parent,false);
        return new MyViewHolder(view);
    }

也可以寫為

@NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_rv_card,parent,false);
        return new MyViewHolder(view);
    }

一樣的。

5.2為每一項檢視,新增資料。

此處holder為你每一項的MyViewHolder物件,position 定位,可以理解為list下標。

@Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.tvId.setText(position);
        holder.tvState.setText(position+position);
    }

5.3返回列表大小

@Override
    public int getItemCount() {
        return 0;
    }

第六步,建立資料介面

建立一個List列表(當然也可以是JsonArray),以此為例,我們創一個Card實體類,為List新增該類泛型。

 

 

 6.1接下來在CardAdapter建立一個帶該list的構造器

List<Card> list;

    public CardAdapter(List<Card> list) {
        this.list = list;
    }

6.2在getItemCount方法中返回該列表大小

  @Override
  public int getItemCount() {
    return list == null ? 0 : list.size();
  }

6.3在onBindViewHolder方法中繫結真實資料

  @Override
  public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
    holder.tvId.setText(list.get(position).getId());
    holder.tvState.setText(list.get(position).getState());
  }

以下為整體程式碼(文末有我在使用RecycleView中對Adapter的改進程式碼,如有需要可以參考):

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;

/** @Author: Messi Mei @Date: 2020/8/24 13:46 @Email: 709909986@qq.com */
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.MyViewHolder> {
  private List<Card> list;

  public CardAdapter(List<Card> list) {
    this.list = list;
  }

  @NonNull
  @Override
  public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_rv_card, parent, false);
    return new MyViewHolder(view);
  }

  @Override
  public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
    holder.tvId.setText(list.get(position).getId());
    holder.tvState.setText(list.get(position).getState());
  }

  @Override
  public int getItemCount() {
    return list == null ? 0 : list.size();
  }

  static class MyViewHolder extends RecyclerView.ViewHolder {
    private TextView tvId, tvState;

    MyViewHolder(@NonNull View itemView) {
      super(itemView);
      tvId = itemView.findViewById(R.id.tv_id);
      tvState = itemView.findViewById(R.id.tv_state);
    }
  }
}

第七步,使用RecycleView

在Activity中建立RecycleView物件並繫結檢視,建立Adapter物件。

在initData中初始化資料。

package com.mz.myapplication;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
  private RecyclerView recyclerView;
  private CardAdapter cardAdapter;
  private List<Card> list;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initData();
    initView();
  }

  private void initData() {
      list = new ArrayList<>();
    for (int i = 0; i < 50; i++) {
        Card card = new Card();
        card.setId(i+1+"");
        if (i%2 == 1){
            card.setState("線上");
        }else{
            card.setState("離線");
        }
        list.add(card);
    }
  }

  private void initView() {
    recyclerView = findViewById(R.id.rv_card);
    cardAdapter = new CardAdapter(list);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(cardAdapter);
  }
}

至此,執行即可。

如果你想要更復雜的列表佈局,在佈局檔案中加入相應的檢視即可,修改完後記得在ViewHolder中加入、繫結相應的檢視,在Adapter中的onBindViewHolder為其新增、繫結資料。

 

而我更推薦以下這種方式,用set方法去設定Adapter中的資料,更加靈活。

package com.mz.myapplication;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

/** @Author: Messi Mei @Date: 2020/8/24 13:46 @Email: 709909986@qq.com */
public class Card2Adapter extends RecyclerView.Adapter<Card2Adapter.MyViewHolder> {
  private List<Card> list = new ArrayList<>();

  public void setList(List<Card> list) {
    this.list = list;
  //一定要記得加 notifyDataSetChanged(); } @NonNull @Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_rv_card, parent, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { holder.tvId.setText(list.get(position).getId()); holder.tvState.setText(list.get(position).getState()); } @Override public int getItemCount() { return list == null ? 0 : list.size(); } static class MyViewHolder extends RecyclerView.ViewHolder { private TextView tvId, tvState; MyViewHolder(@NonNull View itemView) { super(itemView); tvId = itemView.findViewById(R.id.tv_id); tvState = itemView.findViewById(R.id.tv_state); } } }
package com.mz.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;

import java.util.ArrayList;
import java.util.List;

public class Main2Activity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private Card2Adapter card2Adapter;
    private List<Card> list;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        initView();
        initData();
    }
    private void initData() {
        list = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            Card card = new Card();
            card.setId(i+1+"");
            if (i%2 == 1){
                card.setState("線上");
            }else{
                card.setState("離線");
            }
            list.add(card);
        }
        card2Adapter.setList(list);
    }

    private void initView() {
        recyclerView = findViewById(R.id.rv_card);
        card2Adapter = new Card2Adapter();
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(card2Adapter);
    }
}

這樣你可以在任意位置修改列表中的資料。

相關文章