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.

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




相关文章
|
5天前
|
IDE Android开发 iOS开发
探索Android与iOS开发的差异:平台选择对项目成功的影响
【9月更文挑战第27天】在移动应用开发的世界中,Android和iOS是两个主要的操作系统平台。每个系统都有其独特的开发环境、工具和用户群体。本文将深入探讨这两个平台的关键差异点,并分析这些差异如何影响应用的性能、用户体验和最终的市场表现。通过对比分析,我们将揭示选择正确的开发平台对于确保项目成功的重要作用。
|
18天前
|
Android开发 开发者 Kotlin
探索安卓开发中的新特性
【9月更文挑战第14天】本文将引导你深入理解安卓开发领域的一些最新特性,并为你提供实用的代码示例。无论你是初学者还是经验丰富的开发者,这篇文章都会给你带来新的启示和灵感。让我们一起探索吧!
|
2天前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
18 7
|
5天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台解决方案
【9月更文挑战第27天】在移动应用开发的广阔天地中,安卓和iOS两大操作系统如同双子星座般耀眼。开发者们在这两大平台上追逐着创新的梦想,却也面临着选择的难题。如何在保持高效的同时,实现跨平台的开发?本文将带你探索跨平台开发的魅力所在,揭示其背后的技术原理,并通过实际案例展示其应用场景。无论你是安卓的忠实拥趸,还是iOS的狂热粉丝,这篇文章都将为你打开一扇通往跨平台开发新世界的大门。
|
2天前
|
缓存 Java Linux
探索安卓开发:从新手到专家的旅程
【9月更文挑战第30天】在这篇文章中,我们将一起踏上一段激动人心的旅程,探索安卓开发的广阔世界。无论你是刚入门的新手,还是希望提升技能的开发者,本文都将为你提供宝贵的知识和指导。我们将深入探讨安卓开发的基础知识、关键概念、实用工具和最佳实践,帮助你在安卓开发领域取得更大的成功。让我们一起开启这段精彩的旅程吧!
|
3天前
|
监控 安全 Java
Kotlin 在公司上网监控中的安卓开发应用
在数字化办公环境中,公司对员工上网行为的监控日益重要。Kotlin 作为一种基于 JVM 的编程语言,具备简洁、安全、高效的特性,已成为安卓开发的首选语言之一。通过网络请求拦截,Kotlin 可实现网址监控、访问时间记录等功能,满足公司上网监控需求。其简洁性有助于快速构建强大的监控应用,并便于后续维护与扩展。因此,Kotlin 在安卓上网监控应用开发中展现出广阔前景。
7 1
|
13天前
|
Android开发 开发者
安卓开发中的自定义视图:从入门到精通
【9月更文挑战第19天】在安卓开发的广阔天地中,自定义视图是一块充满魔力的土地。它不仅仅是代码的堆砌,更是艺术与科技的完美结合。通过掌握自定义视图,开发者能够打破常规,创造出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战应用,一步步展示如何用代码绘出心中的蓝图。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往创意和效率的大门。让我们一起探索自定义视图的秘密,将你的应用打造成一件艺术品吧!
38 10
|
7天前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
|
15天前
|
Java Linux Android开发
深入理解Android开发:从基础到高级
【9月更文挑战第17天】本文将深入探讨Android开发的各个方面,包括应用开发、操作系统等。我们将通过代码示例来展示如何创建一个简单的Android应用,并解释其背后的原理。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和启示。
|
12天前
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
在Android开发中,每位开发者都渴望应用响应迅速、体验流畅。然而,代码执行缓慢却是常见问题。本文将跟随一位大神的脚步,剖析三大典型案例:主线程阻塞导致卡顿、内存泄漏引发性能下降及不合理布局引起的渲染问题,并提供优化方案。通过学习这些技巧,你将能够显著提升应用性能,从新手蜕变为高手。
16 2
下一篇
无影云桌面