今天要來補一個大坑(`▽´)
之前曾做過一篇講述RecycleView的文章
如果還不會RecycleView或者是還不熟悉RecycleView用法的人可以參考這篇喔~
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混合介面
上篇中講述了RecycleView的架構以及基本用法
今天就要來講述RecycleView的另外兩項常用功能
1.點擊事件
2.下拉更新
OK,先上範例
然後一樣是GitHub:
https://github.com/thumbb13555/SimpleRecycleViewExample
功能描述:
1.點擊物件後,以Toast顯示該項目之平均分
2.到頂時,往下拉則再跑一次(更新)分數計算
OK本文開始
RecycleView跟ListVIew不一樣的是,RecycleView的點擊事件並非如同ListView可直接以外部覆寫的方法操作
RecycleView必須得先在ViewHolder內宣告一個View,然後再從onBindViewHolder
內做事件點擊
好啦廢話太多也沒什麼意義,直接上程式
public class mainActivity extends Appcompatactivity{
.
.
.
private class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder>{
class ViewHolder extends RecyclerView.ViewHolder{
private TextView tvId,tvSub1,tvSub2,tvAvg;
private View mView;
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);
mView = itemView;
}
}
@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"));
holder.mView.setOnClickListener((v)->{
Toast.makeText(getBaseContext(),holder.tvAvg.getText(),Toast.LENGTH_SHORT).show();
});
}
@Override
public int getItemCount() {
return arrayList.size();
}
}
}
範例中紅字的部分就是這次點擊事件的範例中新增的部分
可以看見就是簡單的三步驟
1.在class ViewHolder extends RecyclerView.ViewHolder{...底下命一個變數,資料型態為View
2.把這個View跟底下ViewHolder的View綁再一起
3.在onBindViewHolder內宣告setOnClickListener點擊事件
4.完成(・ω・)b
不知解釋至此,有理解了嗎XDDD
好啦既然這麼簡單就趕快實作ㄅ (⌐■_■)
OK接下來是下拉事件
下拉事件實際上直接就有現成的可以用了(・ω・`)………..
只要你不要太挑惕...基本上也很夠用
這個套件叫做SwipeRefreshLayout
效果如同上面的那個Gif...非常地陽春
此外我之前在找資料時,發現一位大大直接全部手寫
https://juejin.im/post/5a22af7a6fb9a0450e75ee61
有機會我也會試試看的C≡(・。・C≡)≡≡≡
OK回歸正題,關於這個SwipeRefreshLayout我們來看看官方範例
https://developer.android.com/training/swipe
以及官方文檔
https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout
其實直接參照官方範例就可以了...XD
OK從範例中可以看到步驟有二
1.在Layout中加入SwipeRefreshLayout
2.在程式碼中呼叫 .setOnRefreshListener
範例在此↓
https://developer.android.com/training/swipe/respond-refresh-request#RespondRefresh
好實作開始。
首先我們要在Layout中加入SwipeRefreshLayout元件
樹狀結構長這樣
基本上大重點就是只要把它包在RecycleView的外圍即可
看一下Xml Code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:background="#4B5A6D"
tools:context=".MainActivity">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/refreshLayout"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycleview"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
網路上有些資料是用Androidx以前的套件寫的,2019的現在用Androidx套件的話直接打
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
即可。
這時候可以執行看看,當你下拉列表時就會有反應囉
(●・ω・)b
只是他的轉圈圈不會消失而已XD
要消滅轉圈圈,就得呼叫這個方法
swipeRefreshLayout.setRefreshing(false);
OK,
接下來回到Code
先PO一下全部
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 androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
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 android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
String TAG = "mExample";
RecyclerView mRecyclerView;
MyListAdapter myListAdapter;
SwipeRefreshLayout swipeRefreshLayout;
ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//製造資料
makeData();
//設置RecycleView
mRecyclerView = findViewById(R.id.recycleview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
myListAdapter = new MyListAdapter();
mRecyclerView.setAdapter(myListAdapter);
//下拉刷新
swipeRefreshLayout = findViewById(R.id.refreshLayout);
swipeRefreshLayout.setColorSchemeColors(getResources().getColor(R.color.blue_RURI));
swipeRefreshLayout.setOnRefreshListener(()->{
arrayList.clear();
makeData();
myListAdapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
});
}//onCreate
private void makeData() {
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);
}
}
private class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder>{
class ViewHolder extends RecyclerView.ViewHolder{
private TextView tvId,tvSub1,tvSub2,tvAvg;
private View mView;
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);
mView = itemView;
}
}
@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"));
holder.mView.setOnClickListener((v)->{
Toast.makeText(getBaseContext(),holder.tvAvg.getText(),Toast.LENGTH_SHORT).show();
});
}
@Override
public int getItemCount() {
return arrayList.size();
}
}
}
來看一下下拉刷新的部分
也就是紅字部分
swipeRefreshLayout = findViewById(R.id.refreshLayout);
swipeRefreshLayout.setColorSchemeColors(getResources().getColor(R.color.blue_RURI))
在swipeRefreshLayout方法內,setColorSchemeColors可以設定圈圈的顏色喔~
接下來來看刷新的部分
swipeRefreshLayout.setOnRefreshListener(()->{
arrayList.clear();
makeData();
myListAdapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
});
因為我們的目的是要更新列表
但是說穿了不過就是重置罷了XD
因此我們把輸出資料的源頭整理成一個副程式
也就是粉字的makeData()的部分
再來,按照步驟處理:
1.清除表單資料:arrayList.clear();
2.載入資料:makeData();
3.通知Adapter資料有被改變:myListAdapter.notifyDataSetChanged();
4.清除轉圈圈:swipeRefreshLayout.setRefreshing(false);
最後補充一下
myListAdapter的資料情別是所定義class的名稱
也就是
private class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder>{...}
的部分
前面有在全域變數中宣告過
MyListAdapter myListAdapter;
別搞錯囉~
(´・д・`)
會特別提醒是因為之前在網路爬文資料更新時
keyPoint打上:notifydatasetchanged not work
還蠻多人有疑問的
像這樣的問題
https://kgnotezone.blogspot.com/2018/01/android-notifydatasetchanged.html
https://stackoverflow.com/questions/15422120/notifydatasetchange-not-working-from-custom-adapter
這兩問題的大意就是忘記改變arrayList的內容..
還有之前也遇過一個蠢(其實還好)問題
淦...為什麼我打上arrayList. 沒有出現notifydatasetchanged啊囧
後來才發現...喔淦那是適配器(Adapter)的方法拉...
...
..
.
今天補完了RecycleView的下拉更新方法,不知道有沒有幫助呢?
程式碼在這兒,可以多多點進去看哦~
https://github.com/thumbb13555/SimpleRecycleViewExample
掰逼~(´-`)ノ