kotlin安卓开发【Jetpack Compose】:封装SnackBarUtil工具类方便使用

简介: GPT-4o 是一个非常智能的模型,比当前的通义千问最新版本在能力上有显著提升。作者让GPT开发一段代码,功能为在 Kotlin 中使用 Jetpack Compose 框架封装一个 Snackbar 工具类,方便调用



大模型返回的代码, 根本就没法用,本篇是一个 badcase。 实际上应该使用Toast,非常简单易用。Toast的具体使用,见文章最后



问题:

kotlin 开发安卓app, 使用Jetpack Compose框架。 帮我封装一个好用的util 工具类, 实现一行代码可以调用snackbar 显示一个简短的信息, 支持 错误类型, 警告类型, 消息类型, 成功类型, 不同的图标加上具体的同时信息一起显示。 几秒后自动消失。



GPT-4o给的回复



为了封装一个实用的工具类,实现一行代码即可调用 Snackbar 显示一个简短的信息,并支持错误类型、警告类型、消息类型、成功类型等不同的图标和信息,可以按照以下步骤进行实现:

  1. 创建一个 SnackbarUtil 工具类。
  2. 定义 SnackbarType 枚举类,表示不同类型的 Snackbar。
  3. 封装 showSnackbar 方法,以便一行代码即可调用 Snackbar。

完整代码示例

定义 SnackbarType 枚举类以及图标资源

首先定义 SnackbarType 枚举类和图标资源,以表示不同类型的 Snackbar 和对应的图标。


import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.ui.graphics.vector.ImageVector

enum class SnackbarType(val icon: ImageVector) {
    ERROR(Icons.Default.Error),
    WARNING(Icons.Default.Warning),
    INFO(Icons.Default.Info),
    SUCCESS(Icons.Default.CheckCircle)
}



创建 SnackbarUtil

接下来,创建 SnackbarUtil 工具类,封装一个用于显示 Snackbar 的方法。



import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

object SnackbarUtil {
    fun showSnackbar(
        scaffoldState: ScaffoldState,
        message: String,
        type: SnackbarType,
        durationMillis: Long = 3000 // Duration can be customized here
    ) {
        val scope = rememberCoroutineScope()
        scope.launch {
            scaffoldState.snackbarHostState.showSnackbar(
                message = message,
                actionLabel = null, // No action button
                duration = SnackbarDuration.Short
            )
            delay(durationMillis)
            scaffoldState.snackbarHostState.currentSnackbarData?.dismiss()
        }
    }
    
    @Composable
    fun CustomSnackbar(snackbarData: SnackbarData, type: SnackbarType) {
        Snackbar(
            modifier = Modifier.padding(8.dp)
        ) {
            Icon(
                imageVector = type.icon,
                contentDescription = null,
                modifier = Modifier.size(24.dp)
            )
            Spacer(modifier = Modifier.size(8.dp))
            Text(text = snackbarData.message)
        }
    }
}



使用 SnackbarUtil 在 UI层

我们在 UI 层调用 SnackbarUtil 来显示不同类型的 Snackbar。示例代码如下:



import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel

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

@Composable
fun MyApp() {
    val scaffoldState = rememberScaffoldState()

    Scaffold(
        scaffoldState = scaffoldState,
        topBar = {
            TopAppBar(title = { Text("Snackbar Example") })
        },
        content = {
            Column(
                Modifier
                    .fillMaxSize()
                    .padding(16.dp),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally
            ) {
                Button(onClick = {
                    SnackbarUtil.showSnackbar(
                        scaffoldState = scaffoldState,
                        message = "Error message",
                        type = SnackbarType.ERROR
                    )
                }) {
                    Text("Show Error")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Button(onClick = {
                    SnackbarUtil.showSnackbar(
                        scaffoldState = scaffoldState,
                        message = "Warning message",
                        type = SnackbarType.WARNING
                    )
                }) {
                    Text("Show Warning")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Button(onClick = {
                    SnackbarUtil.showSnackbar(
                        scaffoldState = scaffoldState,
                        message = "Info message",
                        type = SnackbarType.INFO
                    )
                }) {
                    Text("Show Info")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Button(onClick = {
                    SnackbarUtil.showSnackbar(
                        scaffoldState = scaffoldState,
                        message = "Success message",
                        type = SnackbarType.SUCCESS
                    )
                }) {
                    Text("Show Success")
                }
            }
        },
        snackbarHost = {
            SnackbarHost(
                hostState = scaffoldState.snackbarHostState,
                snackbar = { snackbarData ->
                    SnackbarUtil.CustomSnackbar(snackbarData = snackbarData, type = SnackbarType.INFO) // Pass your type here
                }
            )
        }
    )
}

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



上面有几个问题,

1、不需要CustomSnackbar,这个有点繁琐,没必要。

2、传参数 scafoldState, 应该不需要

3、 type参数也不需要, 直接封装成4个函数,给到用户。


我把上述要求给gpt说了, 最终它给了一个非常完美的代码




好的,我们可以进一步简化 SnackbarUtil,将 showSnackbarError、showSnackbarInfo、showSnackbarWarning 和 showSnackbarSuccess 四个函数分离出来,这样调用者就不需要传递 type 参数了。

更新后的 SnackbarUtil 工具类

SnackbarType 枚举类(保留用于内部)


工具类


import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

object SnackbarUtil {
    @Composable
    private fun showSnackbar(
        message: String,
        type: SnackbarType,
        durationMillis: Long = 3000 // Duration can be customized here
    ) {
        val scaffoldState = rememberScaffoldState()
        val coroutineScope = rememberCoroutineScope()
        
        LaunchedEffect(key1 = message) {
            coroutineScope.launch {
                scaffoldState.snackbarHostState.showSnackbar(
                    message = message,
                    actionLabel = type.label,
                    duration = SnackbarDuration.Short
                )
                delay(durationMillis)
                scaffoldState.snackbarHostState.currentSnackbarData?.dismiss()
            }
        }

        // Connect this to the actual Scaffold in your UI
        Scaffold(snackbarHost = {
            SnackbarHost(hostState = scaffoldState.snackbarHostState)
        }) {}
    }

    @Composable
    fun showError(message: String, durationMillis: Long = 3000) {
        showSnackbar(message, SnackbarType.ERROR, durationMillis)
    }

    @Composable
    fun showWarning(message: String, durationMillis: Long = 3000) {
        showSnackbar(message, SnackbarType.WARNING, durationMillis)
    }

    @Composable
    fun showInfo(message: String, durationMillis: Long = 3000) {
        showSnackbar(message, SnackbarType.INFO, durationMillis)
    }

    @Composable
    fun showSuccess(message: String, durationMillis: Long = 3000) {
        showSnackbar(message, SnackbarType.SUCCESS, durationMillis)
    }
}





使用 SnackbarUtil 在 UI 层

在实际的 UI 组件中调用 SnackbarUtil 来显示不同类型的 Snackbar:



import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

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

@Composable
fun MyApp() {
    Scaffold(
        topBar = {
            TopAppBar(title = { Text("Snackbar Example") })
        },
        content = {
            Column(
                Modifier
                    .fillMaxSize()
                    .padding(16.dp),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Button(onClick = {
                    SnackbarUtil.showError("Error message")
                }) {
                    Text("Show Error")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Button(onClick = {
                    SnackbarUtil.showWarning("Warning message")
                }) {
                    Text("Show Warning")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Button(onClick = {
                    SnackbarUtil.showInfo("Info message")
                }) {
                    Text("Show Info")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Button(onClick = {
                    SnackbarUtil.showSuccess("Success message")
                }) {
                    Text("Show Success")
                }
            }
        },
        snackbarHost = { SnackbarHost(hostState = rememberScaffoldState().snackbarHostState) }
    )
}

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



解释:

  1. SnackbarType 枚举类:保留用于内部表示不同类型的 Snackbar,并且为每种类型指定了一个标签和图标。
  2. SnackbarUtil:
  • showSnackbar 私有组合函数:这是一个私有方法,现在所有具体类型的 Snackbar 都通过这个方法显示。
  • showError、showWarning、showInfo、showSuccess 组合函数:以上函数调用 showSnackbar,传递相应的 SnackbarType,这样调用者就不需要传递 type 参数了。
  1. MyApp 组件:
  • 使用 Scaffold 来搭建基本页面布局。
  • 每个按钮点击时会分别调用 SnackbarUtil.showError、SnackbarUtil.showWarning、SnackbarUtil.showInfo 和 SnackbarUtil.showSuccess 显示不同类型的 Snackbar。

通过这种方式,可以更加简洁地调用 SnackbarUtil.showError、SnackbarUtil.showWarning、SnackbarUtil.showInfo 和 SnackbarUtil.showSuccess 方法来显示不同类型的 Snackbar,使代码更加简洁和易于维护。





通义千问给的回复



在Kotlin与Jetpack Compose中,你可以创建一个实用的工具类来简化Snackbar的调用,使其能够通过一行代码展示不同类型的Snackbar消息,并带有自动消失功能。下面是一个示例实现:

SnackbarUtil.kt


package your.package.name.util

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material.icons.rounded.CheckCircle
import androidx.compose.material.icons.rounded.ErrorOutline
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.WarningAmber
import androidx.compose.material.snackbar.SnackbarDuration
import androidx.compose.material.snackbar.SnackbarResult
import androidx.compose.material.snackbar.SnackbarHost
import androidx.compose.material.snackbar.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import kotlinx.coroutines.delay

enum class SnackbarType {
    ERROR, WARNING, INFO, SUCCESS
}

object SnackbarUtil {
    @Composable
    fun showSnackbar(
        message: String,
        type: SnackbarType = SnackbarType.INFO,
        durationMs: Long = SnackbarDuration.Short.durationMillis,
    ) {
        val snackbarHostState = remember { SnackbarHostState() }
        val coroutineScope = remember { androidx.compose.runtime.currentComposer.coroutineScope }
        val context = LocalContext.current

        DisposableEffect(message) {
            LaunchedEffect(Unit) {
                delay(durationMs)
                snackbarHostState.showSnackbar(message = message)
            }

            onDispose {}
        }

        SnackbarHost(snackbarHostState) { data ->
            val icon = when (type) {
                SnackbarType.ERROR -> Icons.Filled.Error
                SnackbarType.WARNING -> Icons.Outlined.Warning
                SnackbarType.INFO -> Icons.Rounded.Info
                SnackbarType.SUCCESS -> Icons.Rounded.CheckCircle
            }

            Box(
                modifier = Modifier.fillMaxWidth(),
                contentAlignment = Alignment.CenterStart
            ) {
                // 在这里可以根据需要添加图标
                // 由于Compose Snackbar目前不直接支持图标,所以这里省略了图标的具体实现
                androidx.compose.material.Snackbar(
                    modifier = Modifier.align(Alignment.CenterStart),
                    action = {},
                    dismissAction = { snackbarHostState.currentSnackbarData?.dismiss() },
                    message = { androidx.compose.material.Text(message) }
                )
            }
        }
    }
}





使用示例

在你的Compose界面中,你可以这样调用SnackbarUtil.showSnackbar方法来显示不同类型的Snackbar:


import your.package.name.util.SnackbarType
import your.package.name.util.SnackbarUtil

// ...

@Composable
fun MyScreen() {
    Column(modifier = Modifier.fillMaxSize()) {
        // ... 其他组件
        Button(onClick = {
            SnackbarUtil.showSnackbar("操作成功", type = SnackbarType.SUCCESS)
        }) {
            Text("显示成功Snackbar")
        }
        Button(onClick = {
            SnackbarUtil.showSnackbar("警告信息", type = SnackbarType.WARNING)
        }) {
            Text("显示警告Snackbar")
        }
        // 类似地,添加更多按钮来测试其他类型的Snackbar
    }
}


在Kotlin与Jetpack Compose中实现Snackbar功能及相关概念,可以参考以下官方文档和资源:

  1. Jetpack Compose官方文档 - Snackbar: 虽然Compose的文档中并没有直接提供一个内置的带图标的Snackbar实现,但它详细介绍了如何使用SnackbarHost和SnackbarHostState来创建和管理Snackbar。
  1. Material Design Guidelines - Snackbars: Google的Material Design指南提供了关于Snackbars的设计原则和使用建议,帮助你理解何时以及如何使用它们。
  1. Compose状态与副作用: 了解如何在Compose中使用DisposableEffect和LaunchedEffect来管理状态和执行副作用,这对于实现定时自动消失的Snackbar非常关键。
  1. Coroutine延迟: 上述示例中使用了delay函数来实现延迟显示Snackbar,这是Kotlin协程的基本功能之一。
  1. 自定义Snackbar: 虽然上述示例中没有深入到如何添加图标,但如果你需要自定义Snackbar样式,包括添加图标,可以参考以下资源:
  1. 图标资源: Material Icons的官方页面,可以查找和下载各种图标资源。




Toast的详细使用


何时在Android应用中使用Toasts? (When to use Toasts in Android app?)

Toast messages are used to show the user something that isn’t critical but might help the user with what’s happening in the application currently. For example, giving a hint for a specific field in the form.

Toast消息用于向用户显示不重要的内容,但可能会帮助用户了解应用程序中当前发生的情况。 例如,为表单中的特定字段提供提示。

创建吐司的语法 (Syntax to Create a Toast)

We can use the Toast class to create a toast message.

我们可以使用Toast类创建一条Toast消息。

1. Toast.makeText(this, "Androidly Short Toasts", Toast.LENGTH_SHORT).show();
2. 
3. Toast.makeText(this, "Androidly Long Toasts", Toast.LENGTH_LONG).show();

Toast requires three arguments.

吐司需要三个参数。

  1. Context语境
  2. Message信息
  3. Duration持续时间

The show() function is used to display the Toast on the screen.

show()函数用于在屏幕上显示Toast。

We can customize the layout of the toast as well as its duration.

我们可以自定义吐司的布局及其持续时间。




相关文章
|
16天前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
40 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
1月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
164 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
26天前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
48 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
2月前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
97 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
12天前
|
安全 Android开发 iOS开发
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。
|
10月前
|
存储 安全 Android开发
构建高效的Android应用:Kotlin与Jetpack的结合
【5月更文挑战第31天】 在移动开发的世界中,Android 平台因其开放性和广泛的用户基础而备受开发者青睐。随着技术的进步和用户需求的不断升级,开发一个高效、流畅且易于维护的 Android 应用变得愈发重要。本文将探讨如何通过结合现代编程语言 Kotlin 和 Android Jetpack 组件来提升 Android 应用的性能和可维护性。我们将深入分析 Kotlin 语言的优势,探索 Jetpack 组件的核心功能,并通过实例演示如何在实际项目中应用这些技术。
|
9月前
|
数据管理 API 数据库
探索Android Jetpack:现代安卓开发的利器
Android Jetpack是谷歌为简化和优化安卓应用开发而推出的一套高级组件库。本文深入探讨了Jetpack的主要构成及其在应用开发中的实际运用,展示了如何通过使用这些工具来提升开发效率和应用性能。
|
8月前
|
存储 数据库 Android开发
🔥Android Jetpack全解析!拥抱Google官方库,让你的开发之旅更加顺畅无阻!🚀
【7月更文挑战第28天】在Android开发中追求高效稳定的路径?Android Jetpack作为Google官方库集合,是你的理想选择。它包含多个独立又协同工作的库,覆盖UI到安全性等多个领域,旨在减少样板代码,提高开发效率与应用质量。Jetpack核心组件如LiveData、ViewModel、Room等简化了数据绑定、状态保存及数据库操作。引入Jetpack只需在`build.gradle`中添加依赖。例如,使用Room进行数据库操作变得异常简单,从定义实体到实现CRUD操作,一切尽在掌握之中。拥抱Jetpack,提升开发效率,构建高质量应用!
150 4
|
10月前
|
Java 数据库 Android开发
构建高效Android应用:Kotlin与Jetpack的完美结合
【5月更文挑战第28天】 在现代移动开发领域,Android平台以其广泛的用户基础和开放性受到开发者青睐。随着技术的不断进步,Kotlin语言以其简洁性和功能性成为Android开发的首选。而Android Jetpack组件则为开发者提供了一套高质量的设计架构、工具和UI组件,以简化应用程序的开发过程。本文将探讨如何利用Kotlin语言和Android Jetpack组件共同构建一个高效的Android应用程序,涵盖从语言特性到架构模式的全面分析,并提供具体的实践指导。
|
9月前
|
Android开发
Jetpack Compose: Hello Android
Jetpack Compose: Hello Android