iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
0
自我挑戰組

Kotlin Everyday:新手寫程式踩的坑系列 第 16

Day 16 ─用 Kotlin 做待辦清單 Todolist(1) 使用Menu+RecycleView


做一個 Todolist,按右上角按鈕會跳到第二個頁面,有一個 EditText 可輸入待辦事項,確認點選後會跳回原先的頁面,此時第一頁會多出一行剛剛新增的事項。

使用:Activity 切換、RecycleView、Adapter、Menu等

這些使用到的元件多半是之前寫過的功能,語法和 layout 的部分會略過,來練習看著上面這張 gif 圖把他們寫出來(會備註在哪個 .kt 檔):

1. 新增按鈕(MainActivity.kt)

單純切換的功能,只要設定跳轉到下一個頁面就好,不過因為等下會讀取夾帶回來的資料,所以在 Menu Item 要設定可以返回--- startActivityForResult

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.menu, menu)
    return super.onCreateOptionsMenu(menu)
}       //menuInflater

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    item.itemId == R.id.menu_add
    startActivityForResult(Intent(this, Main2Activity::class.java),1)
    return super.onOptionsItemSelected(item)
}       //MenuItem

2. 夾帶資料(Main2Activity.kt)

從第一頁跳過來之後,會有一個 EditText 要輸入、兩個按鈕分別為確認 (check) 及取消鍵 (cancel),這邊要注意:

  • 限制使用者要輸入文字才能確認新增
  • 按「取消」會回到上一頁

(1) 確認鍵

  • 當 editText 為空白時,Toast 提醒使用者輸入文字---editText2.text.isBlank()
  • 使用 Bundle 夾帶資料:Bundle.putStringIntent.putExtras
  • setResult 要回傳 RESULT_OK 和夾帶資料
btn_check.setOnClickListener {
    if (editText2.text.isBlank())
        Toast.makeText(this, "請輸入待辦事項", Toast.LENGTH_SHORT).show()
    else {
        val b = Bundle()
        b.putString("todo", "${editText2.text}")
        val intent1 = Intent()
        intent1.putExtras(b)
        setResult(Activity.RESULT_OK, intent1)
        finish()
        
        Toast.makeText(this, "${editText2.text}儲存成功", Toast.LENGTH_SHORT).show()
    }
}

(2) 取消返回鍵

之前沒有注意 finish() 用法,查了一下才知道 startActivityForResult 和 startActivity 其中一個差異在於跳轉頁面的返回,如果用後者要跳轉回去只能再使用一次 startActivity()?

startActivityForResult 則不同,它可以調用 finish() 這個用法來一次性完成,也只有寫這行時 Activity 才會返回,看上面程式碼就會發現 setResult() 被寫在 finish() 前面!所以

  • setResult() 是用來回傳數據,不會馬上返回
  • 更多疑問可以參考這篇,它最後提到實際應用常會有設定 Back 事件
btn_cancel.setOnClickListener {
finish()   //取消鍵就調用 finish() 方法
}

3. RecycleView 及 Adpater 設定(Adapter.kt)

主頁 RecycleView 清單是用來顯示回傳資料的,而 RecycleView 在之前 Day 8 ─用Kotlin RecycleView做一個ImageList 講過,繼續來練習它、熟悉它,這次顯示的資料內容比較簡單,只有一行字串(上次是圖片+文字):

Step 1. 定義資料
在 Adpater.kt 定義 Thing 為 String 型態的資料

data class Thing(val todo: String)

Step 2. 繼承 Adpater
class 繼承 RecyclerView.Adapter<>,添加一個泛型 <ViewHolder>,讓其繼承 RecyclerView.ViewHolder,裡面定義等下會使用到的元件和函式(inner class)

class MyAdapter(private val things:ArrayList<Thing>) :
RecyclerView.Adapter<MyAdapter.ViewHolder>(){
    
    inner class ViewHolder(v: View):RecyclerView.ViewHolder(v){
        val tv_todo = v.findViewById<TextView>(R.id.tv_todo)
        
        fun bind(todo: String){
            tv_todo.setText(todo)  
        }     //等下會在onBindViewHolder方法執行它
    }
}

綁定 itemView 裡面的 TextView(findViewById

Step 3. 完成 Adapter 待執行的三個方法

  • onCreateViewHolder()
    初始化 RecyclerView 子項目畫面佈局,使用 inflater 方法
inflate(resource: Int, root: ViewGroup?, attachToRoot: Boolean): View!
  • getItemCount()
    取得子項目資料總數
  • onBindViewHolder()
    更新 RecyclerView.ViewHolder 內容,綁定數據資料
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
    val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.activity_my_adapter, viewGroup, false)
    return ViewHolder(view)
}
override fun getItemCount() = things.size

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bind(things[position].todo)
    //把 function bind 指給 holder

Step 4. 呈現 RecycleView(MainActivity.kt)
先定義 adapter 和things,等下讀取返回資料時要用到

private lateinit var adapter : MyAdapter 
private var things = ArrayList<Thing>()

把 adapter 和 layoutManager 指給 RecycleView來呈現

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    adapter = MyAdapter(things)
    recycleview.layoutManager = LinearLayoutManager(this)
    recycleview.adapter = adapter
}

4. 覆寫 onActivityResult 接收資料(MainActivity.kt)

在 2. 就把資料夾帶跳轉回主頁,主頁的 RecycleView也做好,剩下最後一步驟是接收並讀取在bundle裡面的字串,不清楚流程的可以去 Day 4 ─用Kotlin做點餐介面 (2) intent 複習記憶:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
        
        // requestCode 和 resultCode
        if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
            val todo = data?.extras?.getString("todo")
            things.add(Thing(todo!!))
            
        // 必須調用這個方法才能刷新清單內容
            adapter.notifyDataSetChanged()
        }
}

今天整合很多之前練習的東西,包括 Menu、 RecycleView 和 Activity 夾帶資料的用法,是一個很實用的題目,明天會針對 Todolist 添加更多功能!


上一篇
Day 15 ─用 Kotlin Fragment 做底部導覽欄 (2)
下一篇
Day 17 ─用 Kotlin 做待辦清單 Todolist(2) SharedPreferences 上篇
系列文
Kotlin Everyday:新手寫程式踩的坑30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言