學以致用,把主畫面組裝起來。
這裡傳三個 funtion 用來做頁面轉換用。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(
onSearchBarClick: () -> Unit,
onAddTrainingClick: () -> Unit,
onTrainingClick: (Long) -> Unit,
) {
}
onSearchBarClick
搜尋欄被點擊時,要跳轉頁面。onAddTrainingClick
新增事件時,要跳轉頁面。onTrainingClick
當事件被點擊時,要跳轉頁面,並且戴上 Training
的 id 值利用 Scaffold 來佈局畫面。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(
//...
) {
Scaffold(
topBar = {//... },
floatingActionButton = {//...}
) { padding -> //... }
}
topBar
放搜尋欄floatingActionButton
新增事件的懸浮按鈕padding
自動算好扣除 topBar
的 padding
距離。帶入最外層的 composable
modifier.padding
就可以用了搜尋欄位
TopAppBar(
modifier = Modifier
.clickable { onSearchBarClick() }
.padding(8.dp),
title = {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = "",
onValueChange = {},
placeholder = {
Text(text = "搜尋")
},
shape = CircleShape
)
}
)
modifier
設置了clickable
點擊就跳轉頁面,padding
上下左右外距8.dp
OutlinedTextField
呈現placeholder
提示字串,並且將外型shape
改為原型。因為要跳轉頁面 value
值不特別紀錄,onValueChange
也不處理。新增訓練的懸浮按鈕
import androidx.compose.material.icons.filled.Add
floatingActionButton = {
FloatingActionButton(onClick = { onAddTrainingClick() }) {
Icon(Icons.Filled.Add, contentDescription = "Add Training")
}
}
採用 FloatingActionButton
,onClick
lambda
放入 onAddTrainingClick()
來跳轉頁面。Button content
使用 material icon filled
樣式的 add
。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(
//...
) {
Scaffold(
//...
) { padding ->
//1.check data is not empty
if (trainingList.isEmpty()) {
Text(modifier = Modifier.fillMaxSize(), text = "來安排訓練菜單吧!")
} else {
LazyVerticalGrid(//...) { //2.
items(trainingList) { training ->
//...
}
}
}
}
}
LazyVerticalGrid
在 items
傳入 trainingList
,lambda
就能使用 training
資料。{ padding ->
LazyVerticalGrid(
modifier = Modifier
.padding(padding)//1.
.padding(horizontal = 16.dp),
columns = GridCells.Fixed(2),//2.
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
//...
}
}
LazyVerticalGrid
是最上層的 composable
帶入 Scaffold
的 padding
在 modifier
可以扣除 topAppBar 的高。columns
設置欄位數為 2horizontalArrangement
和 verticalArrangement
用 spacedBy
調整 item 和 item 之間的距離為 8.dp
TrainingCard 負責呈現一個訓練的卡片資訊
items(trainingList) { training ->
TrainingCard(
onCardClick = { id ->
onTrainingClick(id) //1.
},
training = training
)
}
onTrainingClick
可以轉跳頁面並且帶上 training
id
TrainingCard 運用了 Card 、Text 元件還有 Column 來佈局。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TrainingCard(
onCardClick: (Long) -> Unit,
training: Training
) {
Card(
onClick = {
onCardClick(training.id)
},
) {
Column(
modifier = Modifier.padding(8.dp)
) {
Card(
shape = CircleShape,
colors = CardDefaults.cardColors(containerColor = Color.Gray),
modifier = Modifier.fillMaxWidth()
) {
Text(
text = training.date.format(formatter),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(4.dp),
color = Color.White
)
}
Text(
text = training.trainingContext,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(8.dp)
)
}
}
}
指定日期樣式
val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd (E)", Locale.TAIWAN)
今天將 main 頁面調整完,還剩下在 navigation 的資料處理,以及將 training list 從 Data 層串到 ViewModel。以及 GridLayout 在左右兩側高度不同時沒有自動適應高度。
今日運動
休息