一、Hello Compose!
在职务概况界面中,咱们需求将对植物的说明搬迁到Compose,同时让界面的整体结构坚持完好。这时,您需求遵从“规划搬迁”部分中提到的“搭配运用Compose和View”搬迁策略。
Compose需求有宿主activity或fragment才干呈现界面。在Sunflower中,一切界面都运用fragment,因而您需求运用ComposeView
:这一AndroidView能够运用其setContent办法保管Compose界面内容。
1.1、移除XML代码
咱们先从搬迁开端!翻开fragment_plant_detail.xml
并执行以下操作:
- 切换到代码视图
- 移除
NestedScrollView
中的ConstraintLayout
代码和嵌套的TextView
- 增加一个ComposeView,它会改为保管Compose代码,并以
compose_view
作为视图ID
fragment_plant_detail.xml
<androidx.core.widget.NestedScrollView
android:id="@+id/plant_detail_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="@dimen/fab_bottom_padding"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
// Step 2) Comment out ConstraintLayout and its children
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/margin_normal">
<TextView
android:id="@+id/plant_detail_name"
...
</androidx.constraintlayout.widget.ConstraintLayout>
// End Step 2) Comment out until here
// Step 3) Add a ComposeView to host Compose code
<androidx.compose.ui.plantform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.core.widget.NestedScrollView>
1.2、增加Compose代码
现在,您能够开端将植物概况界面搬迁到Compose了!
整个操作中,您都需求将Compose代码增加到plantdetail
文件夹下的PlantDetailDescription.kt
文件中。翻开该文件,看看项目中是否有占位符"Hello Compose!"
文本。
plantdetail/PlantDetailDescription.kt
@Composable
fun PlantDetailDescription() {
Text("Hello Compose")
}
咱们从在上一步中增加的ComposeView
中调用此可组合项,即可在界面上显现此内容。翻开plantdetail/PlantDetailFragment.kt
。
界面运用的是数据绑定,因而您能够直接拜访composeView
并调用setContent
,以便在界面上显现Compose代码。您需求在MaterialTheme
内调用PlantDetailDescription
可组合项,因为Sunflower运用的是Material Design。
plantdetail/PlantDetailFragment.kt
class PlantDetailFragment: Fragment() {
...
override fun onCreateView(...): View? {
val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>(inflater, R.layout.fragmebt_plant_detail, container, false).apply {
...
composeView.setContent {
// You're in Compose world!
MaterialTheme {
PlantDetailDecription()
}
}
}
...
}
}
如果您运转该应用,界面上会显现”Hello Compose!”
二、运用XML创建可组合项
咱们首要搬迁植物的称号。更切当地说,便是您在fragment_plant_detail.xml
中移除的ID为@+id/plant_detail_name
的TextView
。XML代码如下:
<TextView
android:id="@+id/plant_detail_name"
...
android:layout_marginStart="@dimen/margin_small"
android:layout_marginEnd="@dimen/margin_small"
android:gravity="center_horizontal"
android:text="@{viewModel.plant.name}"
androiid:textAppearance="?attr/textAppearanceHeadline5"
... />
请查看它是否为textAppearanceHeadline5
款式,水平外边距为8.dp
,以及是否在界面上水平居中。不过,要显现的标题是由代码库层的PlantDetailViewModel
公开的LiveData
中调查到的。
怎么调查LiveData
将在稍后介绍,因而先假定咱们有可用的称号,并以参数形式将其传递到咱们在PlantDetailDescription.kt
文件中创建的新PlantName
可组合项。稍后,将从PlantDetailDescription
可组合项调用此可组合项。
PlantDetailDescription.kt
@Composable
private fun PlantName(name: String) {
Text(
text = name,
style = MaterialTheme.typography.h5,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = dimensionResource(R.dimen.margin_small))
.wrapContentWidth(Alignment.CenterHorizontally)
)
}
@Preview
@Composable
private fun PlantNamePreview() {
MaterialTheme {
PlantName("Apple")
}
}
其间:
-
Text
的款式为MaterialTheme.typography.h5
,它从XML代码映射到textAppearanceHeadline5
-
修饰符会修饰Text,以将其调整为类似于XML版本:
-
fillMaxWidth
修饰符对应于XML代码中的android:layout_width="match_parent"
-
margin_small
的水平padding
,其值是运用。dimensionResource
辅佐函数从View系统获取的。 -
wrapContentWidth
水平对其Text
。留意:Compose提供了从
dimens.xml
和strings.xml
文件获取值的简略办法,即dimensionResource(id)
和stringResource(id)
。由此一来,您能够将View系统视为可信来源。
三、ViewModel和LiveData
现在,咱们将标题链接到界面。如需执行此操作,您需求运用PlantDetailViewModel
加载数据。为此,Compose集成了ViewModel和LiveData。
3.1、ViewModel
因为fragment中运用了PlantDetailViewModel
的实例,因而咱们能够将其作为参数传递给PlantDetailDescription
,就这么简略。
留意:如果您遇到了ViewModel无法运用的状况,或者您不许忘将该依赖项传递给可组合项,则能够在可组合项中运用viewmodel函数,以获取ViewModel的实例。
可组合项没有自己的ViewModel实例,相应的实例将在可组合项和保管Compose代码的生命周期一切者(activity或fragment)之间共享。
翻开PlantDetailDescription.kt
文件,然后将PlantDetailViewModel
参数增加到PlantDetailDescription:
PlantDetailDescription.kt
@Composable
fun PlantDetailDescription(plantDetailViewModel: PlantDetailViewModel) {
...
}
现在,请在从fragment调用此可组合项时传递ViewModel实例:
PlantDetailFragment.kt
class PlantDetailFragment: Fragment() {
...
override fun onCreateView(...): View? {
...
composeView.setContent {
MaterialTheme {
PlantDetailDescription(plantDetailViewModel)
}
}
}
}
3.2、LiveData
有了LiveData,您已有权拜访PlantDetailViewModel
的LiveData<Plant>
字段,以获取植物的称号。
如需从可组合项调查LiveData,请运用LiveData.observeAsState()
函数。
留意:LiveData.observeAsState()
开端调查LiveData,并经过State
对象表示它的值。每次向LiveData发布一个新值时,返回的State
都会更新,这会导致一切State.value
用法重组。
因为LiveData发出的值能够为null,因而您需求将其用法封装在null查看中。有鉴于此,以及为了完结可重用性,最好将LiveData的运用和监听拆分到不同的可组合项中。因而,请创建一个名为PlantDetailContent
的新可组合项,用于显现Plant
信息。
根据以上原因,增加LiveData调查后,PlantDetailDescription.kt
文件将如下所示。
PlantDetailDescription.kt
@Composable
fun PlantDetailDescription(plantDetaiViewModel: PlantDetailViewModel) {
// Observes values coming from the VM's LiveData<Plant> field
val plant by PlantDetailViewModel.plant.observeAsState()
// If plant is not null, display the content
plant?.let {
PlantDetailContent(it)
}
}
@Composable
fun PlantDetailContent(plant: Plant) {
PlantName(plant.name)
}
@Preview
@Composable
private fun PlantDetailCOntentPreview() {
val plant = Plant("id", "Apple", "description", 3, 30, "")
MaterialTheme {
PlantDetailContent(plant)
}
}
预览与PlantNamePreview
相同,因为PlantDetailContent
现在只调用PlantName
:
现在,您已完结在Compose中显现植物称号所需的一切ViewModel链接。在接下来的几部分中,您将构建其余可组合项,并以类似的方式将它们里链接到ViewModel。