Android控制元件 RecyclerView簡單使用
阿新 • • 發佈:2021-01-02
RecyclerView 很強大很好用,直接開整。
一、RecyclerView 準備工作
- Gradle 中引入 dependencies 閉包
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
- 修改 activity_main.xml,配置按鍵 和 RecyclerView 控制元件 layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="新增資料"
android:onClick="onAddDataClick"/>
<Button
android:layout_width="match_parent"
android: layout_height="wrap_content"
android:text="切換佈局"
android:onClick="onChangeLayoutClick"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="插入一條資料"
android:onClick="onInsertDataClick"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="刪除一條資料"
android:onClick="onRemoveDataClick"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
- 新建一個類繼承 RecyclerView.Adapter
- 並且建立一個內部類 MyViewHolder 傳入 RecyclerView.Adapter 泛型
- 重寫 MyRecyclerViewAdapter 抽象方法
public class MyRecyclerViewAdapter extends
RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder,final int position) {
}
@Override
public int getItemCount() {
}
//建立一個MyViewHolder繼承RecyclerView.ViewHolder
class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(@NonNull View itemView) {
super(itemView);
}
}
}
二、配置 Adapter 內部方法
- 新建一個 layout_item.xml 用於作 Adapter 的 item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="#A4D3EE">
<ImageView
android:id="@+id/image_view"
android:layout_width="88dp"
android:layout_height="88dp"
android:scaleType="fitXY"
/>
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="22sp"
android:textColor="#FFF"
android:gravity="center"
android:layout_marginStart="8dp"/>
</LinearLayout>
- 載入佈局,建立一個 ViewHolder
//建立並且返回 ViewHolder
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//建立layout.layout_item,繫結View,返回ViewHolder給onBindViewHolder
View view = LayoutInflater.from(mContext).inflate(R.layout.layout_item,
parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
- 從 ViewHolder 中 findViewById
//建立一個MyViewHolder繼承RecyclerView.ViewHolder
class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
//這裡提出MyViewHolder中的View來做點選事件處理
View itemView;
//onCreateViewHolder中建立MyViewHolder物件,傳入View
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.image_view);
textView = itemView.findViewById(R.id.text_view);
this.itemView = itemView;
}
}
- 繫結資料
//繫結資料
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder,final int position) {
//4.通過onCreateViewHolder傳來的ViewHolder來進行資料來源設定
holder.textView.setText(dataSource.get(position));
holder.imageView.setImageResource(getIcon(position));
}
- 建立資料來源
private final Context mContext;
private List<String> dataSource;
//或者layout_item佈局設定為vertical,然後隨機textView字串的長度
public MyRecyclerViewAdapter(Context context) {
//初始化資料來源,否則getItemCount會出現空指標
this.dataSource = new ArrayList<>();
this.mContext = context;
}
//設定資料來源
public void setDataSource(List<String> dataSource) {
this.dataSource = dataSource;
notifyDataSetChanged();
}
//這裡使用自定義的五張圖片迴圈使用
private int getIcon (int position) {
switch (position % 5) {
case 0:
return R.mipmap.a;
case 1:
return R.mipmap.b;
case 2:
return R.mipmap.c;
case 3:
return R.mipmap.d;
case 4:
return R.mipmap.e;
}
return 0;
}
- 返回資料量
//返回資料量
@Override
public int getItemCount() {
//5.返回資料總量
return dataSource.size();
}
三、顯示資料
- MainActivity 中給 RecyclerView 配置 Adapter
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private MyRecyclerViewAdapter mAdapter;
private List<String> mDataSource = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recycler_view);
//LayoutManager用於指定RecyclerView的佈局方式
//LinearLayoutManager為線性佈局
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//設定RecyclerView的佈局
mRecyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new MyRecyclerViewAdapter(this);
mRecyclerView.setAdapter(mAdapter);
}
//使用按鍵建立並設定資料來源
public void onAddDataClick(View view) {
for (int i = 0; i < 20; i++) {
String s = "第" + i + "條資料";
mDataSource.add(s);
}
mAdapter.setDataSource(mDataSource);
}
}
- 橫向顯示資料,需要在載入 Adapter 之前配置 linearLayoutManager
...
//橫向排列ItemView,最好修改layout_item為vertical
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//資料反向展示(從右向左滑動)
linearLayoutManager.setReverseLayout(true);
...
- 執行結果
四、切換佈局
-
RecyclerView 除了 LinearLayout 外,還有 GridLayout 網格佈局和 StaggeredGridLayout 瀑布流佈局
-
修改 MyRecyclerViewAdapter 構造方法, 新增傳入mRecyclerView用來設定textView隨機高度
private RecyclerView mRecyclerView;
//引數2 傳入mRecyclerView用來設定textView隨機高度;
//或者layout_item佈局設定為vertical,然後隨機textView字串的長度
public MyRecyclerViewAdapter(Context context, RecyclerView mRecyclerView) {
//初始化資料來源,否則getItemCount會出現空指標
this.dataSource = new ArrayList<>();
this.mContext = context;
this.mRecyclerView = mRecyclerView;
}
- 隨機控制元件高度
//獲取TextView隨機高度
private int getRandomHeight() {
return (int)(Math.random() * 1000);
}
- 在 onBindViewHolder 方法增加條件判斷
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder,final int position) {
...
//如果是瀑布流就設定隨機高度
if (mRecyclerView.getLayoutManager().getClass() == StaggeredGridLayoutManager.class) {
LinearLayout.LayoutParams params
= new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getRandomHeight());
holder.textView.setLayoutParams(params);
} else {
LinearLayout.LayoutParams params
= new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
holder.textView.setLayoutParams(params);
}
}
- 修改 MainActivity 中的方法
protected void onCreate(Bundle savedInstanceState) {
...
//onCreate方法中修改
mAdapter = new MyRecyclerViewAdapter(this, mRecyclerView);
...
}
//改變mAdapter的佈局方式
public void onChangeLayoutClick(View view) {
//從線性佈局 --> 網格佈局
if (mRecyclerView.getLayoutManager().getClass() == LinearLayoutManager.class) {
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
mRecyclerView.setLayoutManager(gridLayoutManager);
}
//網格佈局 --> 瀑布流佈局
else if (mRecyclerView.getLayoutManager().getClass() == GridLayoutManager.class) {
StaggeredGridLayoutManager staggeredGridLayoutManager
= new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(staggeredGridLayoutManager);
}
//瀑布流佈局 --> 線性佈局
else if (mRecyclerView.getLayoutManager().getClass() == StaggeredGridLayoutManager.class) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
}
}
五、新增點選事件
- MyRecyclerViewAdapter 中建立 ItemView 點選事件回撥介面
public class MyRecyclerViewAdapter extends
RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {
private OnItemClickListener onItemClickListener;
private OnImageClickListener onImageClickListener;
...
//ItemView點選事件回撥介面
interface OnItemClickListener {
void onItemClick(int position);
}
interface OnImageClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public void setOnImageClickListener(OnImageClickListener onImageClickListener) {
this.onImageClickListener = onImageClickListener;
}
}
- 在 onBindViewHolder 中使用回撥方法
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder,final int position) {
...
//點選事件處理
holder.itemView.setOnClickListener(v -> {
if (onItemClickListener != null) {
//這裡使用回撥方法,具體怎麼使用還得從MainActivity中重寫
onItemClickListener.onItemClick(position);
}
});
holder.imageView.setOnClickListener(v -> {
if (onImageClickListener != null) {
//這裡使用回撥方法,具體怎麼使用還得從MainActivity中重寫
onImageClickListener.onItemClick(position);
}
});
}
- 或者在 onCreateViewHolder 中使用回撥方法
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//建立layout.layout_item,繫結View,返回ViewHolder給onBindViewHolder
View view = LayoutInflater.from(mContext).inflate(R.layout.layout_item,
parent, false);
MyViewHolder holder = new MyViewHolder(view);
//onClick方法寫在onCreateViewHolder中
holder.imageView.setOnClickListener(v -> {
int position = holder.getAdapterPosition();
if (onItemClickListener != null) {
//這裡使用回撥方法,具體怎麼使用還得從MainActivity中重寫
onItemClickListener.onItemClick(position);
}
});
return holder;
}
- MainActivity 重寫回調方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
mAdapter.setOnItemClickListener(position -> {
Toast.makeText(MainActivity.this, "第" + position + "資料被點選", Toast.LENGTH_SHORT).show();
});
mAdapter.setOnImageClickListener(position -> {
Toast.makeText(MainActivity.this, "第" + position + "圖片被點選", Toast.LENGTH_SHORT).show();
});
}
六、增加 \ 刪除 Item
- MyRecyclerViewAdapter 中增加方法
//新增的資料位置,用來改變新加資料的背景色
private int addDataPosition = -1;
//新增一條資料
public void addData(int position) {
addDataPosition = position;
dataSource.add(position, "新增的資料");
//通知插入資料
notifyItemInserted(position);
//通知資料長度變更
// 引數1:是起始位置,從哪裡開始更新,引數2:更新的總數
notifyItemRangeChanged(position, dataSource.size() - position);
//新增資料時滾動到第一行
mRecyclerView.smoothScrollToPosition(position);
}
//刪除一條資料
public void deleteData(int position){
addDataPosition = -1;
dataSource.remove(position);
//通知插入資料
notifyItemRemoved(position);
//通知資料長度變更
// 引數1:是起始位置,從哪裡開始更新,引數2:更新的總數
notifyItemRangeChanged(position, dataSource.size() - position);
}
- 修改 onBindViewHolder 中的程式碼
public void onBindViewHolder(@NonNull MyViewHolder holder,final int position) {
...
//改變新新增的顏色
if (addDataPosition == position) {
holder.itemView.setBackgroundColor(Color.RED);
} else {
holder.itemView.setBackgroundColor(Color.parseColor("#A4D3EE"));
}
}
- MainActivity 中增加方法
public void onRemoveDataClick(View view) {
mAdapter.deleteData(0);
}
public void onInsertDataClick(View view) {
mAdapter.addData(0);
}
七、配置動畫 setItemAnimator
可以參考學習:
https://www.jianshu.com/p/2a82b0341138
八、所有程式碼預覽
MyRecyclerViewAdapter
/**
* 1、繼承RecyclerView.Adapter
* 2、繫結ViewHolder
* 3、實現Adapter的相關方法
*/
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {
private final Context mContext;
private List<String> dataSource;
private RecyclerView mRecyclerView;
private OnItemClickListener onItemClickListener;
private OnImageClickListener onImageClickListener;
//新增的資料位置,用來改變新加資料的背景色
private int addDataPosition = -1;
//引數2 傳入mRecyclerView用來設定textView隨機高度;
//或者layout_item佈局設定為vertical,然後隨機textView字串的長度
public MyRecyclerViewAdapter(Context context, RecyclerView mRecyclerView) {
//初始化資料來源,否則getItemCount會出現空指標
this.dataSource = new ArrayList<>();
this.mContext = context;
this.mRecyclerView = mRecyclerView;
}
//設定資料來源
public void setDataSource(List<String> dataSource) {
this.dataSource = dataSource;
notifyDataSetChanged();
}
//獲取圖片資料
private int getIcon (int position) {
switch (position % 5) {
case 0:
return R.mipmap.a;
case 1:
return R.mipmap.b;
case 2:
return R.mipmap.c;
case 3:
return R.mipmap.d;
case 4:
return R.mipmap.e;
}
return 0;
}
//獲取TextView隨機高度
private int getRandomHeight() {
return (int)(Math.random() * 1000);
}
//建立並且返回 ViewHolder
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//2.建立layout.layout_item,繫結View,返回ViewHolder給onBindViewHolder
View view = LayoutInflater.from(mContext).inflate(R.layout.layout_item,
parent, false);
MyViewHolder holder = new MyViewHolder(view);
//7.onClick方法寫在onCreateViewHolder中
// holder.imageView.setOnClickListener(v -> {
// int position = holder.getAdapterPosition();
// if (onItemClickListener != null) {
// //這裡使用回撥方法,具體怎麼使用還得從MainActivity中重寫
// onItemClickListener.onItemClick(position);
// }
// });
return holder;
}
//繫結資料
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder,final int position) {
//4.通過onCreateViewHolder傳來的ViewHolder來進行資料來源設定
holder.textView.setText(dataSource.get(position));
holder.imageView.setImageResource(getIcon(position));
//8.改變新新增的顏色
if (addDataPosition == position) {
holder.itemView.setBackgroundColor(Color.RED);
} else {
holder.itemView.setBackgroundColor(Color.parseColor("#A4D3EE"));
}
//6.如果是瀑布流就設定隨機高度
if (mRecyclerView.getLayoutManager().getClass() == StaggeredGridLayoutManager.class) {
LinearLayout.LayoutParams params
= new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getRandomHeight());
holder.textView.setLayoutParams(params);
} else {
LinearLayout.LayoutParams params
= new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
holder.textView.setLayoutParams(params);
}
//7.點選事件處理
holder.itemView.setOnClickListener(v -> {
if (onItemClickListener != null) {
//這裡使用回撥方法,具體怎麼使用還得從MainActivity中重寫
onItemClickListener.onItemClick(position);
}
});
holder.imageView.setOnClickListener(v -> {
if (onImageClickListener != null) {
//這裡使用回撥方法,具體怎麼使用還得從MainActivity中重寫
onImageClickListener.onItemClick(position);
}
});
}
//返回資料量
@Override
public int getItemCount() {
//5.返回資料總量
return dataSource.size();
}
//1.建立一個MyViewHolder繼承RecyclerView.ViewHolder
class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
//7.這裡提出MyViewHolder中的View來做點選事件處理
View itemView;
//3.onCreateViewHolder中建立MyViewHolder物件,傳入View
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.image_view);
textView = itemView.findViewById(R.id.text_view);
this.itemView = itemView;
}
}
//7.ItemView點選事件回撥介面
interface OnItemClickListener {
void onItemClick(int position);
}
interface OnImageClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public void setOnImageClickListener(OnImageClickListener onImageClickListener) {
this.onImageClickListener = onImageClickListener;
}
//8.新增一條資料
public void addData(int position) {
addDataPosition = position;
dataSource.add(position, "新增的資料");
//通知插入資料
notifyItemInserted(position);
//通知資料長度變更
// 引數1:是起始位置,從哪裡開始更新,引數2:更新的總數
notifyItemRangeChanged(position, dataSource.size() - position);
mRecyclerView.smoothScrollToPosition(position);
}
//8.刪除一條資料
public void deleteData(int position){
addDataPosition = -1;
dataSource.remove(position);
//通知插入資料
notifyItemRemoved(position);
//通知資料長度變更
// 引數1:是起始位置,從哪裡開始更新,引數2:更新的總數
notifyItemRangeChanged(position, dataSource.size() - position);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private MyRecyclerViewAdapter mAdapter;
private List<String> mDataSource = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recycler_view);
//LayoutManager用於指定RecyclerView的佈局方式
//LinearLayoutManager為線性佈局
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//橫向排列ItemView,最好修改layout_item為vertical
//linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//資料反向展示
//linearLayoutManager.setReverseLayout(true);
//設定RecyclerView的佈局
mRecyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new MyRecyclerViewAdapter(this, mRecyclerView);
mRecyclerView.setAdapter(mAdapter);
//mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// mAdapter.setOnItemClickListener(position -> {
// Toast.makeText(MainActivity.this, "第" + position + "資料被點選", Toast.LENGTH_SHORT).show();
// });
mAdapter.setOnImageClickListener(position -> {
Toast.makeText(MainActivity.this, "第" + position + "圖片被點選", Toast.LENGTH_SHORT).show();
});
}
public void onRemoveDataClick(View view) {
mAdapter.deleteData(0);
}
public void onInsertDataClick(View view) {
mAdapter.addData(0);
}
//改變mAdapter的佈局方式
public void onChangeLayoutClick(View view) {
//從線性佈局 --> 網格佈局
if (mRecyclerView.getLayoutManager().getClass() == LinearLayoutManager.class) {
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
mRecyclerView.setLayoutManager(gridLayoutManager);
}
//網格佈局 --> 瀑布流佈局
else if (mRecyclerView.getLayoutManager().getClass() == GridLayoutManager.class) {
StaggeredGridLayoutManager staggeredGridLayoutManager
= new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(staggeredGridLayoutManager);
}
//瀑布流佈局 --> 線性佈局
else if (mRecyclerView.getLayoutManager().getClass() == StaggeredGridLayoutManager.class) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
}
}
//建立並設定資料來源
public void onAddDataClick(View view) {
for (int i = 0; i < 20; i++) {
String s = "第" + i + "條資料";
mDataSource.add(s);
}
mAdapter.setDataSource(mDataSource);
}
}