Kotlin中compose模式的预览分析

2 阅读7分钟

在 Kotlin 的 Jetpack Compose 里,预览功能是一项强大的工具,它能让开发者在不运行应用程序的情况下查看 Compose UI 组件的外观。
要使用预览功能,需要引入 androidx.compose.ui.tooling.preview 包,然后使用 @Preview 注解标记 Composable 函数。
1,添加相关依赖
在项目级的build.gradle.kts文件中

// Top-level build file where you can add configuration options common to all sub-projects/modules.
// plugins 块用于声明项目要使用的插件。在 Gradle 中,插件可以扩展构建功能,例如添加 Android 应用构建能力、支持 Kotlin 语言等。
plugins {
    // apply false:表示暂时不应用这个插件。
    // 通常在多模块项目中,可能会在根项目的 build.gradle 文件中声明插件,但不在根项目应用,而是在具体的子模块中应用。
    alias(libs.plugins.android.application) apply false
    // 引用 Kotlin Android 插件,该插件使得项目可以使用 Kotlin 语言进行 Android 开发。
    alias(libs.plugins.jetbrains.kotlin.android) apply false
}

// buildscript 块用于配置构建脚本本身的依赖和仓库等信息。
// 在构建 Android 项目时,Gradle 需要使用 Android Gradle 插件来完成诸如编译代码、打包 APK 等任务,因此需要在 buildscript 块中添加该插件的依赖。
buildscript {
    // dependencies 块用于添加构建脚本所需的依赖项。
    // 添加 Android Gradle 插件的依赖
    dependencies {
        // com.android.tools.build:gradle 是 Android Gradle 插件的坐标,8.4.0 是插件的版本号。这个插件提供了构建 Android 应用程序所需的各种任务和功能,例如编译 Java 或 Kotlin 代码、处理资源文件、打包 APK 等。
        classpath("com.android.tools.build:gradle:8.4.0")
    }
}

在模块级的build.gradle.kts(:app)文件中

// plugins 块用于声明项目要使用的插件。
plugins {
    // 使用了 Android 应用程序插件,它允许项目构建成一个 Android 应用程序。libs.plugins.android.application 是通过版本目录(Version Catalog)来引用插件,这样可以更方便地管理插件版本。
    alias(libs.plugins.android.application)
    // 引入 Kotlin Android 插件,使得项目可以使用 Kotlin 语言进行开发。
    alias(libs.plugins.jetbrains.kotlin.android)
}

// android 块包含了 Android 项目的各种配置
android {
    // namespace:指定 Android 项目的命名空间,它类似于之前的 package 声明,用于唯一标识应用程序。
    namespace = "com.eric.rongapplication"
    // compileSdk:指定编译项目时使用的 Android SDK 版本
    compileSdk = 35

    // defaultConfig 块定义了应用程序的默认配置
    defaultConfig {
        // applicationId:应用程序的唯一标识符,在 Google Play 商店等平台上用于区分不同的应用。
        applicationId = "com.eric.rongapplication"
        minSdk = 29
        targetSdk = 35
        // versionCode:应用程序的内部版本号,用于区分不同版本的应用,通常是一个整数。
        versionCode = 1
        // versionName:应用程序对外显示的版本号,如 "1.0"。
        versionName = "1.0"
        // testInstrumentationRunner:指定用于运行 Android 测试的测试运行器
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        // 启用对矢量图形的支持库,这样可以在不同版本的 Android 系统上使用矢量图形。
        vectorDrawables {
            useSupportLibrary = true
        }
    }

    // buildTypes 块定义了不同的构建类型,这里只定义了 release 构建类型。
    buildTypes {
        release {
            // isMinifyEnabled = false:表示在发布版本中不启用代码混淆。代码混淆可以减小应用程序的大小并提高安全性。
            isMinifyEnabled = false
            // proguardFiles:指定用于代码混淆的配置文件
            proguardFiles(
                // getDefaultProguardFile("proguard-android-optimize.txt") 是 Android 提供的默认混淆配置文件,"proguard-rules.pro" 是项目自定义的混淆规则文件。
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    // compileOptions 块用于配置 Java 编译选项。
    compileOptions {
        // sourceCompatibility 和 targetCompatibility 都设置为 JavaVersion.VERSION_1_8,表示项目使用 Java 8 的语法进行编译,并且生成的字节码兼容 Java 8。
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    // kotlinOptions 块用于配置 Kotlin 编译选项。
    kotlinOptions {
        // jvmTarget = "1.8":指定 Kotlin 代码编译生成的字节码兼容 Java 8。
        jvmTarget = "1.8"
    }
    // buildFeatures 块用于启用项目的特定构建功能。
    buildFeatures {
        // compose = true:启用 Jetpack Compose 构建功能,Jetpack Compose 是 Android 的现代声明式 UI 工具包。
        compose = true
    }
    // composeOptions 块用于配置 Jetpack Compose 的编译选项。
    composeOptions {
        // kotlinCompilerExtensionVersion = "1.5.1":指定 Kotlin 编译器扩展的版本,用于支持 Jetpack Compose。
        kotlinCompilerExtensionVersion = "1.5.1"
    }
    // packaging 块用于配置应用程序打包时的资源处理。
    packaging {
        // resources.excludes += "/META-INF/{AL2.0,LGPL2.1}":在打包应用程序时,排除 /META-INF 目录下的 AL2.0 和 LGPL2.1 文件,避免资源冲突。
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}

// dependencies 块用于声明项目的依赖项。
dependencies {
    // implementation:用于添加项目的主要依赖项,这些依赖项会被打包到最终的应用程序中。
    // libs.androidx.core.ktx:AndroidX Core 库的 Kotlin 扩展,提供了一些实用的 Kotlin 扩展函数。
    implementation(libs.androidx.core.ktx)
    // libs.androidx.lifecycle.runtime.ktx:AndroidX Lifecycle 库的 Kotlin 扩展,用于管理组件的生命周期。
    implementation(libs.androidx.lifecycle.runtime.ktx)
    // libs.androidx.activity.compose:用于在 Activity 中使用 Jetpack Compose 的库。
    implementation(libs.androidx.activity.compose)
    // platform(libs.androidx.compose.bom):引入 Jetpack Compose 的物料清单(BOM),确保 Compose 相关库的版本兼容性。
    implementation(platform(libs.androidx.compose.bom))
    // libs.androidx.ui、libs.androidx.ui.graphics、libs.androidx.ui.tooling.preview、libs.androidx.material3:这些都是 Jetpack Compose 相关的库,用于构建 UI 界面。
    implementation(libs.androidx.ui)
    implementation(libs.androidx.ui.graphics)
    implementation(libs.androidx.ui.tooling.preview)
    implementation(libs.androidx.material3)
    // testImplementation:用于添加单元测试的依赖项,这些依赖项只在单元测试时使用
    testImplementation(libs.junit)
    // androidTestImplementation:用于添加 Android 仪器化测试的依赖项,这些依赖项在 Android 设备或模拟器上运行测试时使用。
    // libs.androidx.junit:AndroidX 版本的 JUnit 测试框架。
    androidTestImplementation(libs.androidx.junit)
    // libs.androidx.espresso.core:Espresso 测试框架,用于编写和运行 UI 测试。
    androidTestImplementation(libs.androidx.espresso.core)
    // platform(libs.androidx.compose.bom):同样引入 Jetpack Compose 的 BOM,确保测试环境中 Compose 库的版本兼容性。
    androidTestImplementation(platform(libs.androidx.compose.bom))
    // libs.androidx.ui.test.junit4:用于在 JUnit 4 测试框架中测试 Jetpack Compose UI 的库。
    androidTestImplementation(libs.androidx.ui.test.junit4)
    // debugImplementation:用于添加仅在调试版本中使用的依赖项。
    // libs.androidx.ui.tooling:Jetpack Compose 的工具库,提供了一些调试和预览工具。
    debugImplementation(libs.androidx.ui.tooling)
    // libs.androidx.ui.test.manifest:用于测试 Jetpack Compose UI 的清单文件。
    debugImplementation(libs.androidx.ui.test.manifest)
}

2,编写布局实现类进行预览

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.LayoutDirection
import com.eric.rongapplication.ui.theme.RongApplicationTheme

// ComponentActivity:是 Android 中用于支持 Jetpack Compose 的 Activity 基类
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // enableEdgeToEdge:启用全屏显示,使内容可以延伸到屏幕边缘。
        enableEdgeToEdge()
        // setContent:用于设置 Activity 的内容视图,是 Jetpack Compose 中设置界面的核心方法。
        setContent {
            // RongApplicationTheme,这是自定义的主题,用于统一界面的样式。
            RongApplicationTheme {
                // Scaffold:是一个 Material Design 组件,提供了一个基本的布局结构,如顶部 AppBar、底部导航栏等。
                // Scaffold 是 Jetpack Compose 里的一个 Material Design 组件,其作用是提供基本的布局结构,例如顶部 AppBar、底部导航栏等。
                // Scaffold 接收一个 Lambda 表达式参数,在这个 Lambda 表达式中会提供一个 PaddingValues 类型的参数,这个参数就是 innerPadding。
                Scaffold(
                    modifier = Modifier.fillMaxSize()
                ) {
                    // Scaffold 组件在执行其内容 Lambda 表达式时,会把自身内部的内边距信息封装成一个 PaddingValues 对象,并将其作为参数传递给 Lambda 表达式,也就是 innerPadding。
                    //innerPadding 的值并非固定不变,而是由 Scaffold 的配置和使用场景决定。以下是具体说明:
                    //无额外配置时:若 Scaffold 没有设置顶部 AppBar、底部导航栏等会产生内边距的组件,innerPadding 的所有边距值都为 0。
                    //存在顶部 AppBar 或底部导航栏时:innerPadding 的顶部或底部边距会依据这些组件的高度来确定。例如,要是设置了一个顶部 AppBar,innerPadding 的顶部边距就会等于 AppBar 的高度,这样可以保证内容不会被 AppBar 遮挡。
                    innerPadding ->
                    Log.d("InnerPadding", "Top: ${innerPadding.calculateTopPadding()}, " +
                            "Bottom: ${innerPadding.calculateBottomPadding()}, " +
                            "Start: ${innerPadding.calculateStartPadding(LayoutDirection.Ltr)}, " +
                            "End: ${innerPadding.calculateEndPadding(LayoutDirection.Ltr)}")
                    // Greeting 组合函数:传递了 name 参数为 "Android",并使用 Modifier.padding(innerPadding) 来处理 Scaffold 提供的内边距。
                    EricGreeting(
                        name = "Android",
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }
}

@Composable
fun EricGreeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

// @Preview 注解:用于在 Android Studio 的预览窗口中显示 Greeting 组件的预览效果。showBackground = true 表示显示背景。
// 预览注解的参数可以有name,group,widthDp,heightDp,showSystemUi
// name:为预览设置一个自定义名称,方便在预览窗口中识别。
// group:把多个预览分组,便于在预览窗口中管理。
// widthDp 和 heightDp:指定预览的宽度和高度。
// showSystemUi:显示系统 UI(如状态栏和导航栏)。
@Preview(name = "Eric", group = "group A", widthDp = 150, heightDp = 50, showBackground = true, showSystemUi = false)
@Composable
fun GreetingAndroidPreview() {
    RongApplicationTheme {
        EricGreeting("Android")
    }
}

// 可以为同一个 Composable 函数创建多个预览,每个预览使用不同的参数或配置。
@Preview(showBackground = true)
@Composable
fun GreetingWorldPreview() {
    RongApplicationTheme {
        EricGreeting("World")
    }
}

// 预览复杂组件
// 如果组件依赖于外部状态或者上下文,可以使用 @PreviewParameter 注解提供不同的参数。
@Preview(showBackground = true)
@Composable
// 使用 @PreviewParameter 注解,根据 NameProvider 提供的不同名称生成多个预览。
fun GreetingByParamPreview(@PreviewParameter(NameProvider::class) name: String) {
    EricGreeting(name = name)
}

// NameProvider 类实现了 PreviewParameterProvider 接口,提供了多个不同的名称。
class NameProvider : PreviewParameterProvider<String> {
    override val values = sequenceOf("Alice", "Bob", "Charlie")
}

编译通过,就可以在该文件的编辑页面右上方有三个图标,可以进行编辑、编辑预览、预览的切换。