今天要來聊聊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

在這邊也順便提供我找色卡的網站

https://nipponcolors.com/

這個網站是專門提供日系的配色

如果客官不是什麼色彩學專家,只是個平凡的程序猿的話

與其使用雷到不行的顏色,不如來這個網站找相近的顏色

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;
    }
}

亦可參考官網提供的實作:
https://developer.android.com/guide/topics/ui/layout/recyclerview#Adapter

 

簡單介紹一下三個方法(複寫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的點擊事件與下拉更新的文章在此

懇請支持(・ωー)~☆

http://thumbb13555.pixnet.net/blog/post/312844960-android-studio-%e4%b9%8b%e5%9f%ba%e6%9c%acrecycleview-%e7%94%a8%e6%b3%95-2--%e5%9f%ba%e6%9c%ac%e7%89%88%e4%b8%8b

 

TK2

 
arrow
arrow
    創作者介紹
    創作者 碼農日常 的頭像
    碼農日常

    碼農日常大小事

    碼農日常 發表在 痞客邦 留言(1) 人氣()