首先,要明白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); } }
這樣你可以在任意位置修改列表中的資料。