前篇提到了輸入型的UI元件,但是發現無法正確的反饋結果與改變顯示,這時就需要remember與mutableState來接收並顯示輸入
@Composable
fun App(modifier: Modifier = Modifier) {
Column {
Text("Ok")
Icon(Icons.Default.FavoriteBorder, "")
TextField(
value = "nothing",
onValueChange = {it-> //可省略
Log.d("TextField", "App: $it")
},
label = {Text("TextField")}
)
Button(
onClick = {
Log.d("Button", "App: pressed")
}
) {
Text("Button")
}
}
}
這是目前的程式
在 UI 開發中,你可能會想:「為什麼不直接用一個一般的變數來存放資料,再在需要的地方讀取就好?」
但實際上,這樣做的話 UI 並不會自動更新。
Compose 的核心概念是「聲明式 UI」:畫面顯示的內容,取決於狀態(State)。
當你在 UI 中「讀取」一個狀態值(get
),這個元件就會記住自己依賴了它。
當這個狀態值「被改變」(set
)時,Compose 會自動重新執行相關的 Composable,讓畫面顯示最新的狀態。
換句話說,狀態不只是「存放資料」而已,它還負責「觸發 UI 更新」。
這也是為什麼我們需要 remember { mutableStateOf(...) }
,而不是只用一般變數。
在App底下加入這一行
var counter by remember { mutableStateOf(0) }
Kotlin語法糖:by 是一個快速設定get與set value的方法,請手動將by需要的函數import
然後在按鈕按下的時候讓counter++,這樣就有了可以改變的counter,但是還需要有元件來顯示
所以改造一下Text
應該會長這樣:
@Composable
fun App(modifier: Modifier = Modifier) {
var counter by remember { mutableStateOf(0) }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center //美化排版
) {
Text("Pressed $counter times")
// ......
Button(
onClick = {
// Log.d("Button", "App: pressed")
counter++
}
) {
Text("Button")
}
}
}
現在按鈕按下後,Text的數字會往上增加
這是最最常用的功能與寫法,與上面同樣,可以用mutableStateOf("")
來儲存字串內容
var inputString by remember { mutableStateOf("") }
TextField(
value = inputString,
onValueChange = {it-> //可省略
inputString = it
},
label = {Text("TextField")}
)
這樣子就有一個可以輸入的輸入框了