今天要來聊聊RecycleView(ノ・ェ・)ノ
RecycleView是google在2014年的I/O大會上所推出,其功能可視為是ListVIew的改良版
但是直到我離開學校後,到了現在的2019年才認真開始用RecycleView(´・д・`)
主要是因為唸書時反正作品出來就好了,而且老師也不會特別要我用新技術寫
況且老師自己也沒更新新技術...所以就拖到現在了ORZ
哎算了反正何時開始都不嫌晚~總之現在開始認真學吧XD
RecycleView以初學來說,我感覺ListView比RecycleView稍微簡單一些
實際上,只是需要列表且不再其他功能的話的確如此
但是後來學用了RecycleView之後,發現他的UI設計彈性更大,更有助於客製化
簡單而言就是只要搞懂架構其實就很容易了(`・ω・´)b
但是比起ListView幾行就可以搞定的樣式
RecycleView的設定還是稍微地複雜一些
若客倌想了解極輕量級地使用列表(ListView)的話
不妨可以參考我發的這篇文章
http://thumbb13555.pixnet.net/blog/post/311203469
2020更新:
此外,放上目前本網誌講述過的各種RecyclerView文章,歡迎參考
碼農日常-『Android studio』基本RecyclerView用法
碼農日常-『Android studio』基本RecyclerView 用法-2 基本版下拉更新以及點擊事件
碼農日常-『Android studio』基本RecyclerView 用法-3 RecyclerView上下滑動排序與側滑刪除(RecyclerView Swipe)
碼農日常-『Android studio』基本RecyclerView 用法-4 左滑顯示Button Menu
碼農日常-『Android studio』進階RecyclerView 用法-5 RecyclerView item混合介面
好的廢話到此,上一下範例
以及本次的Github:
https://github.com/thumbb13555/SimpleRecycleViewExample
然後再附上官方範例:
https://developer.android.com/guide/topics/ui/layout/recyclerview
OK,接著描述一下本次的功能
1.以迴圈的方法產生30人(亦可於程式調整)的成績數值
2.科目1與科目2皆是亂數產生
3.平均值是取科目一&科目二的分數下去平均後顯示
4.座號欄會根據平均分數有所變化,變化規則為:
>80 ->綠
<=80 && >60 ->藍
<=60 && >40 ->黃
<=40 ->紅
此外也在這提供四個顏色的色卡
紅:#C73E3A
黃:#FFB11B
綠:#1B813E
藍:#005CAF
在這邊也順便提供我找色卡的網站
這個網站是專門提供日系的配色
如果客官不是什麼色彩學專家,只是個平凡的程序猿的話
與其使用雷到不行的顏色,不如來這個網站找相近的顏色
APP也許會更好看喔!d(>_< )
好了描述完了,接著進到重點吧
整個APP大致兩個部分
1.產生資料
2.將資料放入RecycleView
第一步要來處理RecycleView的準備及前置作業
首先先在build.grade(Module: app)內加入資源檔
接著請在dependencies內加入這兩個資源檔
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.android.support:recyclerview-v7:29.0.0'
最後按下Sync Now載入
再來要來處理準備作業了,首先是畫介面
在layout內除了在欲設定Recycle View的layout內加入Recycle View的元件外
同時也需要再創一個設定每一個View的layout
請參考GitHub內文件
https://github.com/thumbb13555/SimpleRecycleViewExample/tree/master/app/src/main/res/layout
主介面是activity_main.xml
設定View的介面是recycle_item.xml
item的設計長這樣
源碼就自己去Git翻吧,我懶得再貼出來了(*-ω-)
設計完介面後,我們就來到程式的部分
首先請在onCreate的外面設置一個繼承於RecycleView.Adapter的Class
基礎架構長這樣,可以直接複製過去喔
private class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder>{
class ViewHolder extends RecyclerView.ViewHolder{
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
}
亦可參考官網提供的實作:
簡單介紹一下三個方法(複寫OverWrite)
1.onCreateViewHolder:連接剛才寫的layout檔案,return一個View
2.onBindViewHolder:在這裡取得元件的控制(每個item內的控制)
3.getItemCount:取得顯示數量,return一個int,通常都會return陣列長度(arrayList.size)
此外,元件的連結需要在大的class底下再新增一個小的class(橘色部分)
並繼承於RecycleView.ViewHolder
這樣裡面就可以取用方法並在內部連結所需要的控件
設定完RecycleView的控制區域後接著要實作載入的部分了
首先在全域變數內宣告三個東西
RecyclerView mRecyclerView;
MyListAdapter myListAdapter;
ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
寫在onCreate的上面
接著是生成資料的部分
在全域變數中已經宣告用ArrayList包裹住的HashMap了,這裡就來實作把資料包進去
//製造資料
for (int i = 0;i<30;i++){
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("Id","座號:"+String.format("%02d",i+1));
hashMap.put("Sub1",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Sub2",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Avg",String.valueOf(
(Integer.parseInt(hashMap.get("Sub1"))
+Integer.parseInt(hashMap.get("Sub2")))/2));
arrayList.add(hashMap);
}
迴圈跑30次表示30個學生,要跑多少次可以自己去調整
這裡就不多做解釋,得到的資料就是arrayList的變數中,想知道內容可放一個Log去看
接著是RecycleView的設定
//設置RecycleView
mRecyclerView = findViewById(R.id.recycleview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
myListAdapter = new MyListAdapter();
mRecyclerView.setAdapter(myListAdapter);
一樣寫在onCreate內就OK
完成後整體onCreate長這樣
public class MainActivity extends AppCompatActivity {
String TAG = "mExample";
RecyclerView mRecyclerView;
MyListAdapter myListAdapter;
ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//製造資料
for (int i = 0;i<30;i++){
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("Id","座號:"+String.format("%02d",i+1));
hashMap.put("Sub1",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Sub2",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Avg",String.valueOf(
(Integer.parseInt(hashMap.get("Sub1"))
+Integer.parseInt(hashMap.get("Sub2")))/2));
arrayList.add(hashMap);
}
//設置RecycleView
mRecyclerView = findViewById(R.id.recycleview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
myListAdapter = new MyListAdapter();
mRecyclerView.setAdapter(myListAdapter);
}//onCreate
private class....
}
備註:粉色部分的String.format("%02d",i+1)是讓字串補零的方法,供參考(╭ರ_⊙)
完成後接著來到第二階段,設置RecycleView的內容
首先我們在VIEWHOLDER內加入我們每個物件(item)
於是乎我的寫法就是這樣
class ViewHolder extends RecyclerView.ViewHolder{
private TextView tvId,tvSub1,tvSub2,tvAvg;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvId = itemView.findViewById(R.id.textView_Id);
tvSub1 = itemView.findViewById(R.id.textView_sub1);
tvSub2 = itemView.findViewById(R.id.textView_sub2);
tvAvg = itemView.findViewById(R.id.textView_avg);
}
}
紫色的部分是全域變數的部分,然後再連結id時記得要加上粗體字的部分喔
接著把焦點移至下面三個方法
首先先看到onCreateViewHolder,需return一個view
於是我們可以這樣寫
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycle_item,parent,false);
return new ViewHolder(view);
}
利用LayoutInflater方法載入介面
Coding時要小心不要漏掉黑粗字的部分囉
中間的onBindViewHolder先暫時跳過,先看最下面的getCount
getCount方法就是決定顯示數量,通常如果顯示全部就是回傳資料的長度就好
如果是宣告為ArrayList的話就在回傳打上
@Override
public int getItemCount() {
return arrayList.size();
}
如果App需要能手動設定顯示數量,那麼就再自由增減吧
最後回頭來看onBindViewHolder方法
onBindViewHolder方法是用來管控內部元件的操作的
需要準備的材料基本上就是你再onCreate內已經載入好的arrayList
這時候只要善用onBindViewHolder內的兩個傳值,就可以在陣列中取出你要的值並設定囉
傳值1是ViewHolder內的 holder,該用意就是連結剛才宣告過的元件
傳值2是int 的position,簡單來說就像是for迴圈內的那個變數一樣
說了那麼多不如直接看(⌐■_■)
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.tvId.setText(arrayList.get(position).get("Id"));
holder.tvSub1.setText(arrayList.get(position).get("Sub1"));
holder.tvSub2.setText(arrayList.get(position).get("Sub2"));
holder.tvAvg.setText(arrayList.get(position).get("Avg"));
}
像是紅字內我想設定學號的欄位
我只要打上holder.tvId就可以取得他的內容
而因為我這邊需要設定顯示的值
因此呼叫前面的arrayList陣列
取得裡面的ID值
複習一下前面資料的索引
//製造資料
for (int i = 0;i<30;i++){
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("Id","座號:"+String.format("%02d",i+1));
hashMap.put("Sub1",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Sub2",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Avg",String.valueOf(
(Integer.parseInt(hashMap.get("Sub1"))
+Integer.parseInt(hashMap.get("Sub2")))/2));
arrayList.add(hashMap);
}
如同前面把資料包進去,取得資料的時候必須是這樣的語法
arrayList.get(position).get("Id")
可以理解為先拆掉arrayList後,再從裡面的索引去取值
這樣子完成後可以執行看看,看是否每個item都有值了?
最後我們想要實作要求:讓每個平均分數都有不同程度的區分
這時候只要在onBindViewHolder內加入條件判斷就好囉
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
int avgS = Integer.parseInt(arrayList.get(position).get("Avg"));
if (avgS>=80){
holder.tvId.setBackgroundColor(getColor(R.color.green_TOKIWA));
}else if (avgS<80 &&avgS>=60){
holder.tvId.setBackgroundColor(getColor(R.color.blue_RURI));
}else if(avgS<60 &&avgS>=40){
holder.tvId.setBackgroundColor(getColor(R.color.yellow_YAMABUKI));
}else {
holder.tvId.setBackgroundColor(getColor(R.color.red_GINSYU));
}
holder.tvId.setText(arrayList.get(position).get("Id"));
holder.tvSub1.setText(arrayList.get(position).get("Sub1"));
holder.tvSub2.setText(arrayList.get(position).get("Sub2"));
holder.tvAvg.setText(arrayList.get(position).get("Avg"));
}
最後完成了就長這樣
全部的code長這樣:
package com.example.simplerecycleviewexample;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
String TAG = "mExample";
RecyclerView mRecyclerView;
MyListAdapter myListAdapter;
ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//製造資料
for (int i = 0;i<30;i++){
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("Id","座號:"+String.format("%02d",i+1));
hashMap.put("Sub1",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Sub2",String.valueOf(new Random().nextInt(80) + 20));
hashMap.put("Avg",String.valueOf(
(Integer.parseInt(hashMap.get("Sub1"))
+Integer.parseInt(hashMap.get("Sub2")))/2));
arrayList.add(hashMap);
}
//設置RecycleView
mRecyclerView = findViewById(R.id.recycleview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
myListAdapter = new MyListAdapter();
mRecyclerView.setAdapter(myListAdapter);
}//onCreate
private class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder>{
class ViewHolder extends RecyclerView.ViewHolder{
private TextView tvId,tvSub1,tvSub2,tvAvg;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvId = itemView.findViewById(R.id.textView_Id);
tvSub1 = itemView.findViewById(R.id.textView_sub1);
tvSub2 = itemView.findViewById(R.id.textView_sub2);
tvAvg = itemView.findViewById(R.id.textView_avg);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycle_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
int avgS = Integer.parseInt(arrayList.get(position).get("Avg"));
if (avgS>=80){
holder.tvId.setBackgroundColor(getColor(R.color.green_TOKIWA));
}else if (avgS<80 &&avgS>=60){
holder.tvId.setBackgroundColor(getColor(R.color.blue_RURI));
}else if(avgS<60 &&avgS>=40){
holder.tvId.setBackgroundColor(getColor(R.color.yellow_YAMABUKI));
}else {
holder.tvId.setBackgroundColor(getColor(R.color.red_GINSYU));
}
holder.tvId.setText(arrayList.get(position).get("Id"));
holder.tvSub1.setText(arrayList.get(position).get("Sub1"));
holder.tvSub2.setText(arrayList.get(position).get("Sub2"));
holder.tvAvg.setText(arrayList.get(position).get("Avg"));
}
@Override
public int getItemCount() {
return arrayList.size();
}
}
}
結論:
今天實作的算是RecycleView內超級基本的用法
我打算後續再推出RecycleView的其他特技(●`・皿・)
其實這週我coding完實作後才發現忘了加入點擊事件....ORZ
因此可能會再補點擊事件的文章,也應該會增加下拉更新事件的文章
那RecycleView的基礎設置就到這,有問題歡迎討論~
11/30更新:
RecycleView的點擊事件與下拉更新的文章在此
懇請支持(・ωー)~☆
留言列表