5.16

6. 显示商品详情

在此任务中,您将读取并在 Item Details 界面上显示实体详情。您将使用 Inventory 应用数据库中的商品界面状态(例如名称、价格和数量),并使用 ItemDetailsScreen 可组合项在 Item Details 界面上显示这些信息。我们为您预先编写了 ItemDetailsScreen 可组合函数,其中包含三个用于显示商品详情的 Text 可组合项。

ui/item/ItemDetailsScreen.kt

此屏幕是起始代码的一部分,显示了相应商品的详细信息,您会在后续 Codelab 中看到这些商品。您在此 Codelab 中不会处理此界面。ItemDetailsViewModel.kt 是此界面的对应 ViewModel

de7761a894d1b2ab.png

  1. 在 HomeScreen 可组合函数中,请注意 HomeBody() 函数调用。navigateToItemUpdate 将传递给 onItemClick 参数,当您点击列表中的任一商品时,此参数会被调用。
 
// No need to copy over
HomeBody(
    itemList = homeUiState.itemList,
    onItemClick = navigateToItemUpdate,
    modifier = modifier
        .padding(innerPadding)
        .fillMaxSize()
)
  1. 打开 ui/navigation/InventoryNavGraph.kt 并注意 HomeScreen 可组合项中的 navigateToItemUpdate 参数。此参数将导航目的地指定为“Item Details”界面。
 
// No need to copy over
HomeScreen(
    navigateToItemEntry = { navController.navigate(ItemEntryDestination.route) },
    navigateToItemUpdate = {
        navController.navigate("${ItemDetailsDestination.route}/${it}")
   }

我们已为您实现 onItemClick 功能的这一部分。点击列表项后,应用会转到“Item Details”界面。

  1. 点击商品目录列表中的任意商品,即可查看包含空白字段的“Item Details”界面。

包含空白数据的“Item Details”界面

若要使用商品详情填充文本字段,您需要在 ItemDetailsScreen() 中收集界面状态。

  1. 在 UI/Item/ItemDetailsScreen.kt 中,向 ItemDetailsScreen 可组合项添加一个 ItemDetailsViewModel 类型的新参数,并使用工厂方法对其进行初始化。
 
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.inventory.ui.AppViewModelProvider

@Composable
fun ItemDetailsScreen(
    navigateToEditItem: (Int) -> Unit,
    navigateBack: () -> Unit,
    modifier: Modifier = Modifier,
    viewModel: ItemDetailsViewModel = viewModel(factory = AppViewModelProvider.Factory)
)
  1. 在 ItemDetailsScreen() 可组合项内,创建一个名为 uiState 的 val 来收集界面状态。使用 collectAsState() 收集 uiState StateFlow 并通过 State 表示其最新值。Android Studio 会显示未解决的引用错误。
 
import androidx.compose.runtime.collectAsState

val uiState = viewModel.uiState.collectAsState()
  1. 若要解决此错误,请在 ItemDetailsViewModel 类中创建一个名为 uiState 且类型为 StateFlow<ItemDetailsUiState> 的 val
  2. 从商品存储库中检索数据,并使用扩展函数 toItemDetails() 将其映射到 ItemDetailsUiState。我们已经在起始代码中为您编写了扩展函数 Item.toItemDetails()
 
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn

val uiState: StateFlow<ItemDetailsUiState> =
         itemsRepository.getItemStream(itemId)
             .filterNotNull()
             .map {
                 ItemDetailsUiState(itemDetails = it.toItemDetails())
             }.stateIn(
                 scope = viewModelScope,
                 started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
                 initialValue = ItemDetailsUiState()
             )
  1. 将 ItemsRepository 传入 ItemDetailsViewModel 中以解决 Unresolved reference: itemsRepository 错误。
 
class ItemDetailsViewModel(
    savedStateHandle: SavedStateHandle,
    private val itemsRepository: ItemsRepository
    ) : ViewModel() {
  1. 在 ui/AppViewModelProvider.kt 中,更新 ItemDetailsViewModel 的初始化程序,如以下代码段所示:
 
initializer {
    ItemDetailsViewModel(
        this.createSavedStateHandle(),
        inventoryApplication().container.itemsRepository
    )
}
  1. 返回 ItemDetailsScreen.kt,您会发现 ItemDetailsScreen() 可组合项中的错误已解决。
  2. 在 ItemDetailsScreen() 可组合项中,更新 ItemDetailsBody() 函数调用并将 uiState.value 传入 itemUiState 实参。
 
ItemDetailsBody(
    itemUiState = uiState.value,
    onSellItem = {  },
    onDelete = { },
    modifier = modifier.padding(innerPadding)
)
  1. 观察 ItemDetailsBody() 和 ItemInputForm() 的实现。您将当前选定的 item 从 ItemDetailsBody() 传递到 ItemDetails()
 
// No need to copy over

@Composable
private fun ItemDetailsBody(
    itemUiState: ItemUiState,
    onSellItem: () -> Unit,
    onDelete: () -> Unit,
    modifier: Modifier = Modifier
) {
    Column(
       //...
    ) {
        var deleteConfirmationRequired by rememberSaveable { mutableStateOf(false) }
        ItemDetails(
             item = itemDetailsUiState.itemDetails.toItem(), modifier = Modifier.fillMaxWidth()
         )

      //...
    }
  1. 运行应用。当您点击 Inventory 界面上的任何列表元素时,系统会显示 Item Details 界面。
  2. 请注意,界面已不再空白。该界面会显示从商品目录数据库中检索到的实体详情。

包含有效商品详情的“Item Details”界面

  1. 点按 Sell 按钮。毫无反应!

在下一部分中,您将实现 Sell 按钮的功能。

posted @ 2024-06-19 22:19  混沌武士丞  阅读(3)  评论(0编辑  收藏  举报