iT邦幫忙

2026 iThome 鐵人賽

DAY 9
2

配合分支:day09/start,Repo: 按我

必須增加刪除日記的功能,以防暗黑照寫入日記後需要刪掉。今天來簡單粗暴的把每一張照片日記卡片加入「刪除」按鈕。大概像這樣:

https://ithelp.ithome.com.tw/upload/images/20260828/20141615HV7Ag2qEcq.png

加⋯加入按鈕,簡單!來思考流程會怎麼跑。

推論

https://ithelp.ithome.com.tw/upload/images/20260828/201416150MIsFbIILk.png

  1. 照片日記來自於 List<DiaryEntry> 列表,裏面裝著 DiaryEntry
  2. 印出照片的 LazyColumn 一個一個把照片放到畫面上
  3. 為了告訴 List<DiaryEntry> 該把哪個照片移除掉,需要把位置傳回去
  4. 這個「刪除」按鈕的 Callback Function 需要把位置帶回去
  5. 現在 entries 來自於 ViewModel,所以 ViewModel 要提供一個方法來刪照片

實作

加入按鈕

位置從過去 5 天常駐之處開始下手 PhotoDiaryApp。顯示照片日記列表,就從 DiaryList 開始下手。日記在 LazyColumn 之處,藉由一個一個取出 entries ,再慢慢塞 DiaryCard 到畫面上。

https://ithelp.ithome.com.tw/upload/images/20260828/20141615ji14ai93u8.png

簡單粗暴做了按鈕,並將「刪除」按鈕按下去的事件,做成一個 Callback Function。做好之後,在 LazyColumn 用到的地方,就會開始 panic!說需要多一個 callback function。

LazyColumn 除了 items 也有 itemsIndexed (文件) 這個函式可以使用,在印的過程之中,會把現在的 Index (索引,就是現在位置的數值,通常直接講 Index)。可以改成這個,然後把 Index 往回傳。

https://ithelp.ithome.com.tw/upload/images/20260828/20141615gmBYUzpZzF.png

最後回到最上面的 PhotoDiaryApp,來處理這個 Callback Function。讀到這裡是不是越來越有資料流的感覺了呢?

https://ithelp.ithome.com.tw/upload/images/20260828/20141615e0EW6rXqYu.png

更新 DiaryList 被呼叫的地方,補上 onDeleteDiary Callback。先用大括弧 {} 展開就好。ViewModel 還什麼都沒有,需要去把真正的「刪除」補上。

刪除行為

https://ithelp.ithome.com.tw/upload/images/20260828/20141615RHEDDHo222.png

這邊很簡單,請開啟 PhotoDiaryViewModel,加入一個新的 Method 給外面的人用。這裡需要說明一下為何 entries.toMutableList() 要有 toMutableList()

因為 List<DiaryEntry> 是一個 List,裡頭的元素是不能修改的。(我是指 List 順序,或者刪除一個東西,加入一個東西。不是只某一個內容,不能被改),所以先轉成可以被修改的版本,透過index 給 removeAt() 來移除某個位置的元素,再把這個調整後的版本塞回去。

最後,只需要把外面 UI 的 Callback 接上 ViewModel 行為即可。

onDeleteDiary = { displayIndex -> viewModel.deleteDiaryAt(displayIndex) }


配合分支:day09/index-delete,Repo: 按我

效果很讚耶!我有個大膽的想法,何不也把排序做出來呢?拍照的日期,和新增日記的日期可以不同。來做一個排序是用拍照的順序由新到舊排序,好像也挺讚的!

根據簡單粗暴流的做法,「新增日記」的按鈕下加入新的排序按鈕。和「新增日記」表單出現的情形類似,需要用一個狀態 (State) 來控制現在按鈕要顯示什麼文字,這個狀態也會被拿來判斷按下按鈕後的行為。

規劃

新增狀態 isNewestFirst

  • 成立:按鈕顯示「目前:最新在前(切換為原始順序)」,按下去切換為原始順序排列。
  • 不成立:按鈕顯示「目前:原始順序(切換為最新在前)」,按下去切換為最新在前排列。

實作

加入狀態

這個狀態不能因為旋轉而失效,要加入到 ViewModel 之中(有不明白,請參考 Day 08)。

https://ithelp.ithome.com.tw/upload/images/20260828/201416157kvtMxjlte.png

然後,根據這個狀態來回傳列表。因為需要排序不能再讓 UI 直接去取 property。

https://ithelp.ithome.com.tw/upload/images/20260828/20141615kEhDmfJLFV.png

來介紹一個讚的 Kotlin 內建的 function:sortedByDescending ,照著後方 { } 最後回傳的東西為基礎,倒著排。(由大到小)

這邊透過每一則 diaryEntry 的建立時間 createdAt 由大到小排列,在 Android 裡頭,離現在比較近的日子數值越大。藉由此就可以排列出由近到遠的效果。

UI 調整

現來調整日記列表頁面,這一頁頂端要加上「改變排序的按鈕」,要有一個狀態作為依據(不然不知道顯示什麼文字)。

https://ithelp.ithome.com.tw/upload/images/20260828/20141615eLge7VtRS8.png

這一段完成後,就可以回去呼叫 DiaryList 之處,把資料流全部串起來。

https://ithelp.ithome.com.tw/upload/images/20260828/201416152dXSRNN5Fl.png

到此,一切就完成啦!來看看成果如何:

重新排序後,的確是照拍照時間排囉!不過好像有點怪怪的,照時間排之後,按刪除居然刪錯照片了⋯⋯

TL;DR

  • 刪除事件:把「刪除」按鈕按下去的事件做成 Callback;重點是把要刪哪一張這件事傳回去,而不是卡片自己改列表。
  • 位置 / Index(索引):列表裡第幾張的數字;要告訴 List<DiaryEntry> 移除哪一張,必須把這個位置帶回去。
  • itemsIndexedLazyColumn 除了 items 還能用它,印卡片時一併給出目前 Index,才能把位置塞進刪除 Callback。
  • 本章的資料流:從 DiaryCard 的按鈕一路回到 DiaryListPhotoDiaryApp,再交給 ViewModel;刪除是把事件往上傳,不是在畫面當場改資料。
  • List 不能修改List<DiaryEntry> 不能刪、不能改順序;所以先 toMutableList() 變成可以動手的版本。
  • 移除列表元素:用 Index 從可修改列表藉由 removeAt() 拿掉某個位置的元素,再把調整後的列表塞回 ViewModel。
  • ViewModel 的 Method:外面的人不能直接改 entries,要由 ViewModel 提供刪除方法,UI 的 Callback 再接上去。
  • sortedByDescending:Kotlin 內建排序,照後方 { } 回傳的值由大到小排;本章用 createdAt 排出由近到遠。

上一篇
[Day08] 機器轉一下,什麼都沒了
下一篇
[Day10] 請給他一個 id
系列文
我的第一個手作りAndroid App!快樂學習物件導向程式設計!11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
饅頭
iT邦新手 5 級 ‧ 2026-08-28 21:59:16

這共享空間太棒了吧!
感謝大大教學,讓我知道刪除的坑!

AndyAWD iT邦新手 1 級 ‧ 2026-08-28 23:29:02 檢舉

什麼!居然能刪除

你們想知道是什麼共享空間嗎?

我要留言

立即登入留言