完成基本 Todolist 之後,要為它新增一個「編輯」功能,在每筆資料後面都有一個編輯圖案,點選之後會跳到編輯模式,可以修改字串,看似不難的練習卻花了好幾天才看懂,注意練習重點:
細節很多,讓我們一一寫清楚
首先,使用 RecyclerView 可以做出簡潔好用的布局,但是要實現裡面 Item 的點擊事件卻很麻煩、沒有直接方法可以調用,網路上的做法也是看得眼花撩亂,因為這裡資訊量頗多,筆記一下其中一種做法來提醒自己。
最初,我是在 onBindViewHolder() 方法中直接實現點選事件,寫法雖然可行、卻被建議不要這樣寫,最好是把所有用來實現功能的 code 都寫在 MainActivity、而非 Adapter,Adapter是用來連結資料和畫面的。
這個練習,是參考之前在好想工作室的活動 Kotlin EveryWhere 第四週實作的程式碼完成,同時看 android 開發:給 RecyclerView 的 item 新增點選事件稍微了解每個步驟在幹嘛,有興趣的可以先看一遍再跟著做:
1. 新增每筆資料的編輯圖示
在 Day 8 ─做一個ImageList (上) 裡面有寫到每筆資料的素材、怎麼設 Adapter 範例畫面,這次是要在每筆資料中新增一個按鈕,所以打開放畫面樣式的 xml 檔,在 TextView 旁新添加一個鉛筆圖案,要用作編輯內容的點擊按鈕
2. 在 ViewHolder 裡面綁定編輯圖示
回到 MyAdapter.kt 中,到 ViewHolder 去綁 itemView,同時讓這個 img_edit 可以被點擊(尚未設定點擊之後觸發的事)
inner class ViewHolder(v: View):RecyclerView.ViewHolder(v){
val tv_todo = v.findViewById<TextView>(R.id.tv_todo)
val img_edit = v.findViewById<ImageView>(R.id.img_edit)
//綁畫面元件
fun bind(Thing: Thing){
tv_todo.setText(Thing.todo)
img_edit.setOnClickListener{
//為它設一個 setOnClickListener,之後放點擊事件
}
}
}
interface 介面/接口
為 RecyclerView Item 添加點擊,先要認識 interface
介面是一個相關方法的集合,通常能告訴對象要執行的操作有哪些,以及默認情況下如何執行此操作,參考:
interface ItemClickListener{ //自定義一個 ItemClickListener 介面
fun toEdit()
}
private var itemClickListener : ItemClickListener? = null
toEdit()
,這樣一來,可以在點選後轉移到自定義的介面上,如此一來就可以傳到外面的呼叫者(重要!!!)fun bind(Thing: Thing){
tv_todo.setText(Thing.todo)
img_edit.setOnClickListener{
itemClickListener?.toEdit(Thing)
}
}
fun setToEditClickListener(listener : ItemClickListener){ //用以呼叫的
itemClickListener = listener
} //set方法,可以供Activity或Fragment呼叫
補充:以上可參考 RecyclerView給Item新增點選事件
現在來到 MainActivity修改 RecyclerView 程式碼,在裡頭實現點選事件:
Myadapter.setToEditClickListener()
呼叫 Adapter
會被要求填入參數 listener
用 object 實現接口,參考 Kotlin 里那些「不是那么写的」了解 object 其實可以拿來繼承或實現,這時候會被要求實作 interface 裡面的抽象方法,一定要 override
也就是說 interface 裡面的 toEdit()
要被實作出來,讓它執行函式 EditEvent()
Myadapter.setToEditClickListener(object : MyAdapter.ItemClickListener{
override fun toEdit(edit: Thing) { //override
EditEvent(edit) //執行函式 EditEvent()
}
寫一個函式 EditEvent()
切換頁面並且夾帶資料過去(使用 Gson)
Gson 是一種強大的物件轉換,明天會比較仔細講這一部分,簡單來說因為 Thing 是我們自定義的資料格式,雖然目前只有 String 這一項資料型態,但之後可能會增加更多,不可能一項一項putString、putBoolean的傳送,將資料用序列化成 Json 字串。
fun EditEvent(Event: Thing){
val intent = Intent(this, Main2Activity::class.java)
val eventString = Gson().toJson(Event)
intent.putExtra("event", eventString)
startActivityForResult(intent, 1)
}
現在 RecycleView Item 就可以被點擊,實現切換頁面的效果囉!當然,還有很多地方要調整,像是跳到編輯模式時 EditText 要顯示想要修改的文字、區分新增模式和編輯模式等等,明天再繼續講解囉~
後記
這篇 RecyclerView 點擊事件寫得很卡,因為不夠了解語法,花了整整兩天查資料,寫出這篇文章,後來跟 Noya 討論為什麼需要用 interface 來做,而不是直接在 onBindViewHolder 寫出來時,他給我的想法是考慮到「資料取得及層級」:
這次練習的,資料不是存在 Sharepreference、就是從另一個 Activity傳送返回,和以前直接寫在 Adapter 的陣列不一樣,在 Adapter 裡面取不到這些東西,只有在 MainActivity 才能,所以才要透過 interface 或一些方法把點擊事件呼叫過來。