一、Hello Compose!

在职务概况界面中,咱们需求将对植物的说明搬迁到Compose,同时让界面的整体结构坚持完好。这时,您需求遵从“规划搬迁”部分中提到的“搭配运用Compose和View”搬迁策略。

Compose需求有宿主activity或fragment才干呈现界面。在Sunflower中,一切界面都运用fragment,因而您需求运用ComposeView:这一AndroidView能够运用其setContent办法保管Compose界面内容。

1.1、移除XML代码

咱们先从搬迁开端!翻开fragment_plant_detail.xml并执行以下操作:

  1. 切换到代码视图
  2. 移除NestedScrollView中的ConstraintLayout代码和嵌套TextView
  3. 增加一个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!”

搬迁到Jetpack Compose 第二趴

二、运用XML创建可组合项

咱们首要搬迁植物的称号。更切当地说,便是您在fragment_plant_detail.xml中移除的ID为@+id/plant_detail_nameTextView。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")
    }
}

搬迁到Jetpack Compose 第二趴

其间:

  • Text的款式为MaterialTheme.typography.h5,它从XML代码映射到textAppearanceHeadline5

  • 修饰符会修饰Text,以将其调整为类似于XML版本:

  • fillMaxWidth修饰符对应于XML代码中的android:layout_width="match_parent"

  • margin_small的水平padding,其值是运用。dimensionResource辅佐函数从View系统获取的。

  • wrapContentWidth水平对其Text

    留意:Compose提供了从dimens.xmlstrings.xml文件获取值的简略办法,即dimensionResource(id)stringResource(id)

    由此一来,您能够将View系统视为可信来源。

三、ViewModel和LiveData

现在,咱们将标题链接到界面。如需执行此操作,您需求运用PlantDetailViewModel加载数据。为此,Compose集成了ViewModelLiveData

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,您已有权拜访PlantDetailViewModelLiveData<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:

搬迁到Jetpack Compose 第二趴

搬迁到Jetpack Compose 第二趴

现在,您已完结在Compose中显现植物称号所需的一切ViewModel链接。在接下来的几部分中,您将构建其余可组合项,并以类似的方式将它们里链接到ViewModel。

搬迁到Jetpack Compose 第二趴