Jetpack Compose:将 RecycleView 转换为 LazyColumn

这个适合初学者的教程提供了一个如何将这个简单的 RecycleView 应用程序转换为 Jetpack Compose 的示例。

在迁移到 Jetpack Compose 后,我还采取了一些额外的步骤来清理未使用的代码或 xml。

1.删除RecycleView、Layout、Fragment和Library文件

除了RecycleView,您还可以删除片段和布局文件,因为 Jetpack Compose 不需要它们。

删除不需要的源代码

  • MainFragment.kt
  • RecyceViewAdapter.kt
  • ItemViewHolder.kt
  • ItemDiffCallback.kt

删除不需要的布局文件

  • main_activity.xml
  • main_fragment.xml
  • item.xml

删除不需要的构建功能和库

app\build.gradle中,删除数据绑定,因为这不再适用于 Jetpack Compose。

buildFeatures {
    dataBinding true
}

也删除这些依赖项。

dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
    implementation 'androidx.fragment:fragment-ktx:1.4.0'
}

修复 MainActivity.kt 中的编译问题

删除此代码,MainActivity::onCreate()因为您不再需要片段。

setContentView(R.layout.main_activity)
if (savedInstanceState == null) {
    supportFragmentManager.beginTransaction()
        .replace(R.id.container, MainFragment.newInstance())
        .commitNow()
}

您现在应该能够成功构建。

2 设置 Jetpack Compose 库

更新 build.gradle(项目级别)

在内部添加compose_version扩展名,buildScript{ }以便以后可以引用撰写版本。

buildscript {
    ext {
        compose_version = '1.0.5'
    }
    ...
}

更新 app\build.gradle(应用级别)

添加compose构建功能和kotlinCompilerExtensionVersion组合选项。

android {
    ....
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion compose_version
    }
    ....
}

替换implementation 'androidx.appcompat:appcompat:1.4.0'implementation 'androidx.activity:activity-compose:1.4.0'并添加以下 Jetpack Compose 依赖项。

dependencies {
    ...
    implementation 'androidx.activity:activity-compose:1.4.0'
    ...
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
    ...
}

为撰写更新 MainActivity

在 Jetpack Compose 中,你不再需要AppCompatActivity了,你可以直接继承自ComponentActivity

修改MainActivity为直接继承ComponentActivity,覆盖onCreate()和调用SetContent{},允许@composable内部调用任何函数。

class MainActivity : ComponentActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContent {
            // Implement composable function here.  
        }  
    }
}

3. 在 Jetpack Compose 中添加主题

在 Jetpack Compose 中添加主题之前,让我们清理一下colors.xmlthemes.xml.

您只需要themes.xml为 提供颜色android:statusBarColor。所以你保留它并删除其他任何东西。

清理colors.xml 和themes.xml

这些应该是自定义状态栏颜色所需的最少代码。

color.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_700">#FF3700B3</color>
</resources>

themes.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <style name="Theme.RecycleViewDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
    </style>
</resources>

themes.xml(夜间)

<resources xmlns:tools="http://schemas.android.com/tools">
    <style name="Theme.RecycleViewDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
    </style>
</resources>

添加撰写主题

创建ui.theme包文件夹,将Colors.kt, Shape.kt,Type.kt放入该文件夹。

Colors.kt

val Purple200 = Color(0xFFBB86FC)
val Purple500 = Color(0xFF6200EE)
val Purple700 = Color(0xFF3700B3)
val Teal200 = Color(0xFF03DAC5)

Shape.kt

val Shapes = Shapes(
    small = RoundedCornerShape(4.dp),
    medium = RoundedCornerShape(4.dp),
    large = RoundedCornerShape(0.dp)
)

Type.kt

val Typography = Typography(
    body1 = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp
    )
)

Theme.kt

private val DarkColorPalette = darkColors(
    primary = Purple200,
    primaryVariant = Purple700,
    secondary = Teal200
)

private val LightColorPalette = lightColors(
    primary = Purple500,
    primaryVariant = Purple700,
    secondary = Teal200
)

@Composable
fun RecycleViewDemoTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable() () -> Unit
) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }

    MaterialTheme(
        colors = colors,
        typography = Typography,
        shapes = Shapes,
        content = content
    )
}

这些文件允许您自定义 Jetpack Compose 的主题。

要为您的应用程序设置主题,请MainContent()RecycleViewDemoTheme. 代码如下所示:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MainScreen()
        }
    }
}

@Composable
fun MainScreen() {
    RecycleViewDemoTheme {
        MainContent()
    }
}

@Composable
fun MainContent() {
    //Todo: Implement LazyColumn
}

4.添加顶部应用栏

由于您已删除AppCompatActivity,因此不再创建顶部应用栏。您需要使用 Jetpack Compose 创建它。

添加 Scaffold() 可组合函数

要创建顶部应用栏,请使用ScaffoldI()可组合功能。代码如下所示:

@Composable
fun MainScreen() {
    RecycleViewDemoTheme {
        Scaffold(
            topBar = { TopAppBar (title = {Text(stringResource(R.string.app_name))})
            }
        ) {
            MainContent()
        }
    }
}

预览可组合函数

为了预览可组合函数,您添加以下代码:

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MainScreen()
}

编译后,您应该会在右侧看到类似的内容。如果您运行您的应用程序,您应该会看到与预览版相同的 UI。

现在,该应用程序已完全使用 Jetpack Compose 代码实现。此时,UI 与没有回收视图内容的基于视图的 UI 方法完全相同。

5.实现LazyColumn可组合功能

RecycleViewJetpack compose 中的等价物是LazyColumn可组合函数。

严格来说,它们并不相同。LazyColumn并没有真正回收项目 UI。它只是重新创建整个项目 UI。所以理论上RecycleView性能应该比LazyColumn.

它的好处是LazyColumn使用更少的代码,因为RecycleView它有很多样板代码。在此处查看需要执行多少步骤RecyceView

创建 MainViewModel 并传入 MainContent

由于数据即将到来,您可以在将其作为参数传递给可组合函数时使用委托属性MainViewModel创建它。by viewModels MainActivity``MainContent()

MainActivity.kt

class MainActivity : ComponentActivity() {  
    val viewModel by viewModels<MainViewModel>()  

    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContent {  
            MainScreen(viewModel)  
        }  
    }  
}

by viewModels使用,以便在销毁和重新创建MainViewModel实例时不会重新创建实例。MainActivity请参阅此处的说明。

主屏幕.kt

@Composable
fun MainScreen(viewModel: MainViewModel) {
    RecycleViewDemoTheme {
        Scaffold(
            topBar = { TopAppBar (title = {Text(stringResource(R.string.app_name))})
            }
        ) {
            MainContent(viewModel)
        }
    }
}

将 LiveData 转换为状态

在 Jetpack Compose 中,您需要将其转换为LiveData<T>State<T>以便在数据更改或更新时能够正确重组。要转换它,请使用observeAsState() LiveData函数。

在此之前,您需要添加此库依赖项:

implementation "androidx.compose.runtime:runtime-livedata:$compose_version"

转换为 后State<T>,您将值(即List<ItemData>)作为ListContent()可组合函数的参数。

@Composable
fun MainContent(viewModel: MainViewModel) {
    val itemsState = viewModel.items.observeAsState()

    itemsState.value?.let { items ->
        ListContent(items)
    }
}

实现 LazyColumn

由于RecycleViewitem 原始实现填充了整个屏幕宽度并居中对齐,因此您需要执行相同的操作。这可以通过modiferhorizontalAlignment参数来完成LazyColumn

在最后一个参数LazyColumnFunction Literal (Lambda Function) with Receiver。是LazyListScope接收器。

要添加项目(即List<ItemData>),请调用LazyListSciope.items()可组合函数。要添加项目内容,您需要实现ShowItem()仅显示文本的可组合功能。

为了匹配原始RecycleView实现,我们将字体大小设置为34.spFontWeight.Bold

代码如下所示:

@Composable
fun ListContent(items: List<ItemData>) {
    LazyColumn (
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        items(items = items) { item ->
            ShowItem(item)
        }
    }
}

@Composable
fun ShowItem(item: ItemData) {
    Text(
        text = item.id.toString(),
        fontSize = 34.sp,
        fontWeight = FontWeight.Bold
    )
}

更新预览以包括 MainViewModel 创建

由于MainScreen()接受MainViewModel为参数,因此您需要创建它并传递它。

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    val viewModel = MainViewModel()
    MainScreen(viewModel)
}

6. 完成

终于完成了!。RecycleView该应用程序看起来像这样,这与基于视图的 UI 方法完全相同。

如果需要,您还可以通过将MainContent()可组合函数移出到一个更简洁的单独文件来重构代码。

参考

文章来源:https://vtsen.hashnode.dev/convert-recycleview-to-lazycolumn-jetpack-compose

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容