Jetpack Compose干货,如何让Compose Dialog从屏幕任意方向进入

Compose | UI组件(八) | Dialog - 对话框 1. Dialog是最底层的弹框,可以在该组件之上封装 2. AlertDialog组件是Dialog组件更高级的封装组件,它定位好了标题,内容文本,按钮位置 阅读详情

一、前言

来个效果图,基于Compose Dialog,最终要实现的库能力如下:

底部/顶部/左侧/右侧.gif

这里使用的是这个包下面的:
androidx.compose.ui.window.Dialog

androidx.compose.material3.AlertDialog它内部调用的也是androidx.compose.ui.window.Dialog

不想阅读文章的,可以直接滑到文章末尾,我提供了源码和集成指南。

谷歌提供给我们的compose-ui-dialog,并没有看到能够控制从屏幕底部进入的方法,都是最基础的属性和参数。

// androidx.compose.ui.window.Dialog
@Composable
fun Dialog(
    onDismissRequest: () -> Unit,
    properties: DialogProperties = DialogProperties(),
    content: @Composable () -> Unit
) {
  ....
}

// androidx.compose.material3.AlertDialog
@Composable
fun AlertDialog(
    onDismissRequest: () -> Unit,
    confirmButton: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    dismissButton: @Composable (() -> Unit)? = null,
    icon: @Composable (() -> Unit)? = null,
    title: @Composable (() -> Unit)? = null,
    text: @Composable (() -> Unit)? = null,
    shape: Shape = AlertDialogDefaults.shape,
    containerColor: Color = AlertDialogDefaults.containerColor,
    iconContentColor: Color = AlertDialogDefaults.iconContentColor,
    titleContentColor: Color = AlertDialogDefaults.titleContentColor,
    textContentColor: Color = AlertDialogDefaults.textContentColor,
    tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
    properties: DialogProperties = DialogProperties()
) {
 ....
}

扫一眼源码,并没有看到能够控制Dialog从哪个方向弹出来,那么我们应该如何解决这个问题呢,毕竟不能直接使用Dialog我就很难受😁,你们是不是一样,请在评论区留言讨论🖋。

二、默认Dialog能怎么玩

不要认为我在凑字数划水,不过说实话确实有点像,不感兴趣的,可以直接跳到目录三

既然用默认Dialog,那就中规中矩的玩😁,来个守规矩的Dialog示例

@Composable
fun MinimalDialog(onDismissRequest: () -> Unit) {
    Dialog(onDismissRequest = { onDismissRequest() }) {
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .height(200.dp)
                .padding(16.dp),
            shape = RoundedCornerShape(16.dp),
        ) {
            Text(
                text = "This is a minimal dialog",
                modifier = Modifier
                    .fillMaxSize()
                    .wrapContentSize(Alignment.Center),
                textAlign = TextAlign.Center,
            )
        }
    }
}

AlertDialog(
        onDismissRequest = onDismissRequest,
        icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
        title = {
            Text(text = "Title")
        },
        text = {
            Text(
                "This area typically contains the supportive text " +
                        "which presents the details regarding the Dialog's purpose."
            )
        },
        confirmButton = {
            TextButton(
                onClick = {
                   // 自己实现点击事件
                }
            ) {
                Text("Confirm")
            }
        },
        dismissButton = {
            TextButton(
                onClick = {
                   // 自己实现点击事件
                }
            ) {
                Text("Dismiss")
            }
        }
    )

我们可以看到都是基础到不能再基础的参数设置了,改改参数试试?

试试就试试,谁怕谁啊,把第一个Dialog示例的Modifier修饰符修改一下使用fillMaxSize试试咯。

我们看到宽度、高度没有真正的全屏,宽度这个好解决,只需要配置一下DialogProperties(usePlatformDefaultWidth = false) 即可(这里读者自己试试吧),那么高度怎么解决呢?

我们需要延伸到系统栏,众所周知Android目前除了有小横条之外,还保留了虚拟键的三大金刚,如果无法把内容延伸到系统栏,这就不是真的全屏,而是伪全屏啊,看着就难受啊。

有同学又会说:我直接用BottomSheetScaffold不也行吗?自己封装一个BottomSheetContent放在Scaffold组件里面。

这些都要根据不同业务重度封装弹出组件了,有些业务你可能需要xml+composeView的形式,用Dialog具有更通用性。

下面我们来研究一下,如何继续下面的目录内容。

三、Dialog实现分析

打开我们的AndroidDialog.android.kt

@Composable
fun Dialog(
    onDismissRequest: () -> Unit,
    properties: DialogProperties = DialogProperties(),
    content: @Composable () -> Unit
) {
    ...
    val dialog = remember(view, density) {
        DialogWrapper(view, ...).apply {
            setContent(composition) {
                DialogLayout(Modifier.semantics { dialog() }) {
                    currentContent()
                }
            }
        }
    }
    ...
}

我们打开DialogWrapper方法,看到setContentView它内部仍然是window.setContentView(View):

@OptIn(ExperimentalComposeUiApi::class)
private class DialogWrapper(
    private val composeView: View,
    ...
) : ComponentDialog(...){
    init {
      ...
      dialogLayout = DialogLayout(context, window)
      ...
      setContentView(dialogLayout)
     ...
    }
}

然后呢,我们打开DialogLayout看看里面实现了什么:

@Suppress("ViewConstructor")
private class DialogLayout(
    context: Context,
    override val window: Window
) : AbstractComposeView(context), DialogWindowProvider {
    ...
    override fun internalOnMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (usePlatformDefaultWidth) {
            super.internalOnMeasure(widthMeasureSpec, heightMeasureSpec)
        } else {
            val displayWidthMeasureSpec =
                MeasureSpec.makeMeasureSpec(displayWidth, MeasureSpec.AT_MOST)
            val displayHeightMeasureSpec =
                MeasureSpec.makeMeasureSpec(displayHeight, MeasureSpec.AT_MOST)
            super.internalOnMeasure(displayWidthMeasureSpec, displayHeightMeasureSpec)
        }
    }

    override fun internalOnLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.internalOnLayout(changed, left, top, right, bottom)
        val child = getChildAt(0) ?: return
        // 设置WindowManager.LayoutParams
        window.setLayout(child.measuredWidth, child.measuredHeight)
    }

    private val displayWidth: Int
        get() {
            val density = context.resources.displayMetrics.density
            return (context.resources.configuration.screenWidthDp * density).roundToInt()
        }

    private val displayHeight: Int
        get() {
            val density = context.resources.displayMetrics.density
            return (context.resources.configuration.screenHeightDp * density).roundToInt()
        }
    ...
}

我们从上面代码可以看到 usePlatformDefaultWidth = false,不使用平台默认的宽度,可以实现全屏宽度。
代码中我们又看到了内部有2个变量:displayWidth和displayHeight,他们两个返回的值分别是什么意思,建议大家去看源码注释非常详细,注释内容比较多,这里精简一下,大概的意思就是:

即使你调用:Window#setDecorFitsSystemWindows(boolean)

screenWidthDp、screenHeightDp 它返回的width、height
是不包含WindowInsets衬区的大小在内的。

点击查看什么是WindowInsets

e2e-intro.gif

我们是不是可以通过decoreView获取真实的宽度和高度,答案是肯定的,那么我们如何通过Compose实现呢?

四、Dialog从屏幕底部进入

继续上面的内容,我们应该如何获取Window,这里我们需要分别获取2个Window:

一个是Dialog的Window,一个是Activity的Window。

在埋着头写无穷无尽的业务代码的时候😁,任何人都讨厌问十万个为什么问题的同学,因为这个时候人的怒气值是101%的,但是一但闲下来没事做的时候,就喜欢十万个为什么。

理由一:我们不能直接修改dialog.window = activityWindow,即使可以也不能直接使用type不一样晓得不,有人又会问什么type,请读者自己查看源码:window.attributes.type,不可能全部都介绍一遍。

理由二:默认的dialog的window里面的属性无法适应WindowInsets衬区

理由N:你自己想一想…

回到正题,那么如何获取Dialog的Window呢?

细心的同学可能这里已经发现了,因为他是真的在参考源码,阅读文章的,我们上面的代码刚介绍了DialogLayout,不知道你们注意了没,它实现了DialogWindowProvider 接口,而这个接口只有一个变量就是Window,这很重要

interface DialogWindowProvider {
    val window: Window
}

同时我们还看到 DialogLayout 继承 AbstractComposeView,说到这里,我猜应该有同学知道怎么实现了,有点懵的😳,继续往下看。

1、获取Dialog的Window

我们使用Compose的Dialog一般是这样填充视图内容:

Dialog(
    ...
    content = {
       // 这里放可组合项视图
    }
)

如果你不知道Compose UI创建布局绘制的流程,你可以点击查看我这一篇文章,我们可以通过LocalView.current获取当前的AndroidComposeView,刚刚上面讲的内容,忘记的请动动鼠标往上翻一下。

我们定义一个方法返回Dialog的Window的方法:

@Composable
private fun getDialogWindow(): Window? = (LocalView.current.parent as? DialogWindowProvider)?.window

2、获取Activity的Window

我们可以通过Context下手,通过递归的方式,判断是不是Activity,如果是则可以获取window了,那么可以定义如下的方法:

@Composable
private fun getActivityWindow(): Window? = LocalView.current.context.getActivityWindow()

private tailrec fun Context.getActivityWindow(): Window? = when (this) {
    is Activity -> window
    is ContextWrapper -> baseContext.getActivityWindow()
    else -> null
}

3、实现底部动画弹出Dialog

有了上面的内容支撑之后,我们可以往下实现了,首先需要定义一个全屏的Dialog可组合项:

@Composable
private fun DialogFullScreen(
    onDismissRequest: () -> Unit,
    content: @Composable () -> Unit
) {
    Dialog(
        onDismissRequest = onDismissRequest,
        properties = ...,
        content = {
            // 这里放Dialog的窗口内容...
        }
    )
}

一点点加入代码,把获取Window的代码放在content中,然后在SideEffect去更新DialogWindow:

@Composable
private fun DialogFullScreen(...) {
   Dialog(
       ...
       properties = DialogProperties(
           usePlatformDefaultWidth = true,
           decorFitsSystemWindows = false
       ),
       content = {
           val activityWindow = getActivityWindow()
           val dialogWindow = getDialogWindow()  
            SideEffect {
                if (activityWindow != null && dialogWindow != null) {
                    val attributes = WindowManager.LayoutParams()
                    // 复制Activity窗口属性
                    attributes.copyFrom(activityWindow.attributes)
                    // 这个一定要设置
                    attributes.type = dialogWindow.attributes.type
                    // 更新窗口属性
                    dialogWindow.attributes = attributes

                    // 设置窗口的宽度和高度,这段代码Dialog源码中就有哦,可以自己去查看
                    dialogWindow.setLayout(
                        activityWindow.decorView.width,
                        activityWindow.decorView.height
                    )
                }
            }    
       }
    )
}

可能这个时候又有同学疑问了,不对啊,怎么上面你说宽度铺满,告诉我们usePlatformDefaultWidth设置false,这里怎么是设置为true了?

问的好,请看源码,设置false,会走源码内部的新测量分支,会使用displayWidth、displayHeight,这个是不含WindowInsets衬区的,因为它的 mode = MeasureSpec.AT_MOST,所以这里我们不用,不然竖屏高度,或者横屏宽度,你懂得,还需要再说的更详细嘛,大家都懂的。

这个时候我们如果设置完Dialog内容视图之后,你会发现,Dialog自带的变暗背景色和点击空白区关闭Dialog失效了,并且是没有动画的,我们这个时候可以使用AnimatedVisibility来让内容通过动画的形式进入屏幕。

什么时候执行动画呢,我们只需要在dialogWindow.setLayout代码后面更新visible状态变量就行了。

AnimatedVisibility(
    modifier = Modifier.pointerInput(Unit) {},
    visible = isAnimateLayout,
    enter = slideInVertically(initialOffsetY = { it }),
    exit = fadeOut() + slideOutVertically(targetOffsetY = { it }),
) {
   content()
}

然后暗色背景渐入渐出,我们加个蒙层背景视图即可,使用Animatable更新暗色背景渐入渐出。

大家自行润色一下代码细节就可以使用了,源码在文章目录五查看:

    DialogFullScreen(
        onDismissRequest = onDismiss,
        properties = properties
    ) {
        Column(
            modifier = modifier.navigationBarsPadding(),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            content()
        }
    }

我们再更新一下代码,增加控制方向的属性,这样就可以控制它是从:底部/顶部/左侧/右侧 弹出。

如果是屏幕中间弹出,建议你直接使用默认的Dialog可组合项即可。

同样的,增加控制方向的属性之后,只需要更新AnimatedVisibility即可。

底部/顶部/左侧/右侧.gif

五、如何集成

1、源码

AnyPopDialog-Compose

2、集成

点击👉🏻查看依赖库最新版本号👈🏻

implementation("io.github.TheMelody:any_pop_dialog_compose:<最新版本号>")

3、用法

@Composable
fun TestXXXX() {
    var showDialog by remember { mutableStateOf(false) }
    if (showDialog) {
        var isActiveClose by remember { mutableStateOf(false) }
        AnyPopDialog(
            modifier = Modifier.fillMaxWidth().background(...),
            isActiveClose = isActiveClose,
            // 根据你自己的功能,调整进入方向即可,支持:TOP/LEFT/RIGHT/BOTTOM
            // 也可以配置修改"状态栏"和"导航栏"背景色哦,自己查看方法注释即可
            properties = AnyPopDialogProperties(direction = DirectionState.BOTTOM),
            content = {
                // 这里放你自己的Dialog内容
                // 如果你需要在你自己的组件中想动画关闭Dialog,请更新isActiveClose
            },
            onDismiss = { showDialog = false }
        )
    }
    ...
}
JetpackCompose中的Dialog、AlertDialog 跟View体系一样,Compose中也用Dialog做提示框的。既然有这个API,那我们还是得卷起来熟悉下使用流程及方法。 阅读详情

相关推荐

从入门到进阶:Jetpack Compose 之 对话框组件深度详解(Material 3 版)

Jetpack Compose对话框提供了两种实现方式:AlertDialog遵循Material Design标准,包含预设布局(标题、文本、按钮等);Dialog则是基础组件,支持完全自定义。两者都采用状态驱动机制,通过布尔变量控制显示/隐藏。AlertDialog适用于90%的业务弹窗场景,而Dialog适合复杂UI需求。开发时建议将显示逻辑放在ViewModel中,处理好输入框的键盘遮挡问题(使用DialogProperties(decorFitsSystemWindows=false)),并确保对

郭宝的博客 366

Android Compose 使用 Dialog

Android Compose 使用 Dialog。

Ghlerrix的博客 2614

【GAN实战】基于pytorch-CycleGAN与pix2pix的自定义数据集训练全攻略

本文详细解析了基于PyTorch的CycleGAN与pix2pix模型在自定义数据集上的完整训练流程。核心在于根据数据是否成对来正确选择模型:pix2pix适用于严格配对的“孪生”数据,而CycleGAN则擅长处理非配对的“散装”数据集。文章从数据准备、配置训练到测试应用,提供了全链路实战指南与关键参数调优心得,帮助开发者高效实现图像到图像的风格转换。

x2y3z4a5b的博客 704

Compose笔记(六)--Dialog

这一节主要了解一下Compose中用到的Dialog,Dialog 是用于创建模态对话框的重要组件,它会阻止用户与对话框背后的界面进行交互...

ljt2724960661的博客 732

ANSYS 有限元分析 支架拓扑优化设计 分析过程及常见问题解决

1.确定分析类型,所用模块包括两种 static structural Topology Optimization。3.通过草图建立几何模型,建好的几何模型如图1所示。2.工程材料采用默认的Q235。

m0_68737530的博客 1966

GhidrAssist:AI驱动的逆向工程助手实战指南

逆向工程是分析软件内部工作原理、理解二进制代码逻辑的关键技术,广泛应用于软件安全、恶意代码分析和漏洞挖掘等领域。其核心原理在于通过反编译、控制流与数据流分析等手段,将机器码还原为可理解的高级语言表示。传统逆向分析高度依赖人工经验,面对海量代码时效率低下且易出错。随着大语言模型(LLM)技术的发展,其强大的代码理解与推理能力为自动化逆向分析提供了新的可能。通过将LLM与成熟的逆向工程框架(如Ghidra)相结合,可以构建智能辅助系统,实现代码意图的自动解释、变量/函数的智能重命名以及潜在漏洞模式的辅助识别,从

weixin_42547335的博客 596

Android 知识体系

Android归档前言 前言 感谢: Gityuan:Android系统架构开篇 刘望舒的博客:知识体系

许浑的博客 8197

别再死记硬背了!用LTspice和Simulink仿真,5分钟搞懂巴特沃斯、切比雪夫、贝塞尔滤波器的区别

本文通过LTspice和Simulink仿真工具,直观对比了巴特沃斯、切比雪夫和贝塞尔滤波器的特性差异。从通带波纹、过渡带陡峭度到相位线性度,详细解析了三种经典滤波器的设计哲学与应用场景,帮助工程师和学生快速掌握滤波器选型技巧,提升电路设计效率。

weixin_33910191的博客 523

19. Compose一些难用的控件(Dialog、TextField)

又爱又恨的Compose

u010436867的博客 3699

制作3D地形图的方法-使用GlobalMapper和3ds Max软件

打开GlobalMapper软件,在菜单栏中选择“文件”>“打开数据文件”,然后选择相应的高程数据文件。在菜单栏中选择“渲染”>“渲染设置”,根据需要进行设置,如分辨率和输出格式。选择地形对象,点击菜单栏中的“渲染”>“材质编辑器”,然后根据需要调整材质属性,如颜色、纹理和光照等。在菜单栏中选择“工具”>“高程栅格和网格”>“创建地形网格”。在菜单栏中选择“文件”>“导出”>“导出栅格格式”。打开3ds Max软件,在菜单栏中选择“文件”>“导入”,然后选择之前导出的地形数据文件。步骤3:导出地形网格。

JqlScala的博客 1535

【系统分析师】写作框架:软件设计模式及其应用

本文围绕"软件设计模式及其应用"展开论述。首先介绍了近三年参与的某软件开发项目背景及个人承担的系统设计工作。其次系统阐述了设计模式的三大分类:创建型(如工厂方法、单例模式)、结构型(如适配器、装饰器模式)和行为型(如观察者、策略模式),重点分析了各类模式的特点和典型应用场景。最后结合项目实践,详细说明了采用的三种设计模式的具体实施过程及效果,包括提高代码复用性、降低耦合度等优势。文章还总结了项目经验,指出存在的不足及改进方向,强调合理运用设计模式对构建高质量软件系统的重要性。全文通过理论

数据知道的博客 5061

JetpackCompose从入门到实战学习笔记7—Dialog的简单使用

AlertDialog组件是Dialog组件的更高级别的封装,同时遵循着Material Design 设计标准。它已经帮我们定位好了标题、内容文本、按钮组的位置。

u012556114的博客 1246

optee技术简介

OP-TEE(Open Portable Trusted Execution Environment)是一种开源的可信执行环境(TEE),专为ARM TrustZone架构设计。TEE是一种独立的执行环境,运行在主操作系统之外,为敏感任务提供安全的计算空间,如加密、身份验证、密钥管理等。

baron-周贺贺-代码改变世界ctw 1279

Kotlin——jetpackCompose按钮弹出dialog、列表(类似recyclerView)、双向绑定--列表(可单选/多选)、列表选中显示边框(最简单的方式)

package com.example.jetpackcompose import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose....

wy313622821的博客 7621

基于YOLOv11的仓库机器人导航系统设计与实现:Amazon Robotics Challenge解决方案

本文将详细介绍一个基于YOLOv11目标检测算法的仓库机器人导航系统,该系统能够准确识别托盘(pallet)和箱子(box),为机器人提供精确的导航信息。而基于深度学习的视觉导航系统能够实时识别环境中的关键物体,如托盘和箱子,从而实现更智能的路径规划和货物搬运。YOLOv11作为YOLO系列的最新演进版本,在检测精度和速度上都有显著提升,非常适合仓储环境中的实时物体检测任务。YOLOv11在保持实时性的同时,提高了对小物体和密集物体的检测能力,这对仓储环境中的托盘和箱子检测尤为重要。

YOLO 303

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

使用 Jetpack Compose 创建自定义的对话框(Dialog)

在 Jetpack Compose 中,对话框(Dialog)是一种常见的用户界面组件,用于展示重要的信息、确认操作或者收集用户输入。本篇博客将带你深入了解 Jetpack Compose 中的对话框,并展示如何创建自定义的对话框,以满足你的独特需求。综上所述,Jetpack Compose 提供了强大而灵活的工具,帮助我们创建自定义的对话框。除了基本的对话框,Jetpack Compose 还提供了丰富的自定义选项,使我们能够创建符合特定需求的个性化对话框。的状态,用于控制对话框的显示与隐藏。

江小白的博客 3784

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Android开发之Compose基础学习-Dialog基本用法-可以自己定义布局

【代码】Android开发之Compose基础学习-Dialog基本用法-可以自己定义布局。

xiayiye5的博客 695

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Jetpack Compose底部对话框库——BottomSheetDialog的全新体验!

Jetpack Compose底部对话框库——BottomSheetDialog的全新体验! 项目地址:https://gitcode.com/gh_mirrors/bo/bottomsheetdialog-compose 在Android开发中,设计出优雅的底部弹出对话框(BottomSheetDialog)一直是个挑战,但今天我们要向您推荐一款强大的开源库——HolixFactory的bott...

gitblog_00064的博客 865

Android Compose Dialog唤起键盘后,键盘遮挡Dialog底部内容或者底部TextField顶起不完美的解决方法

Android Compose Dialog唤起键盘后,键盘遮挡Dialog底部内容或者底部TextField顶起不完美的解决方法

City_Coder的博客 5127

探索Compose Material Dialogs:构建优雅对话框的现代Kotlin库

探索Compose Material Dialogs:构建优雅对话框的现代Kotlin库 在Android应用开发中,对话框是与用户交互的重要元素之一。它们用于提示信息、确认操作或提供选择。随着Jetpack Compose的出现,UI开发变得更加现代化和高效。而今天我们要介绍的是一个基于Jetpack Compose的库,它为开发者提供了创建符合Material Design规范的对话框的便利。...

gitblog_00054的博客 670

Jetpack Compose - AlertDialog

Jetpack Compose - AlertDialog0、介绍1、属性一览2、使用示例3、版本更新4、未解决问题 Compose系列文章,请点原文阅读。原文,是时候学习Compose了! 0、介绍 AlertDialog是一个用紧急信息,详细信息或操作打断用户的对话框。 1、属性一览 【目前基于alpha09版本】请看该对话框支持的两个函数,首先看第一个函数,该函数会根据可用空间水平放置其按钮: @Composable fun AlertDialog( onDismissRequest:

乐翁龙 3840

优雅地实现 Dialog 弹窗

可能早就有人已经发现了,我们现在对话框的调用方式跟 Compose,React 很相似,也就是最近很流行的声明式 UI,为什么说它流行,比我们传统的命令式UI好用,主要的差别就在于声明式UI调用方只需要在乎视图的描述就可以,而真正视图如何渲染,如何测量,调用方不需要关心。

chuyouyinghe的专栏 1154

如何快速掌握缠论可视化:通达信Indicator插件的终极指南

你是否曾经面对复杂的K线图感到困惑?是否听说过缠论技术分析但觉得门槛太高?今天我要分享一个能让你在3分钟内上手的专业级缠论可视化工具——通达信Indicator插件。这个基于C++开发的免费开源缠论可视化插件,能将抽象的缠论理论转化为直观的K线图表信号,让普通投资者也能轻松掌握专业级技术分析能力。 ## 项目核心价值:让缠论分析变得简单直观 通达信Indicator插件是一个专为缠论学习者设计

gitblog_00006的博客 850

Jetpack Compose Dialog 进出动画

Compose Dialog 自定义进出动画

DengDongQi的博客 369

【Compose】隐藏Dialog 组件遮罩层

ok,了解各个属性的含义以后,发现并没有直接控制遮罩层的属性存在。但是usePlatformDefaultWidth属性可以控制是否使用系统平台默认的弹窗宽度,那么我们是不是就可以通过自定义一个占满全屏,但是背景透明的内置组件来实现需求呢?然后发现是Material3主题的问题(Material3主题自带的涟漪-水波纹效果应该也可以通过下面这种方法解决):在项目的XML文件中找到主题配置文件的位置,然后修改该文件。属性很简单,明显properties是关键的配置,所以我们来看一下它的属性。

bald_tang的博客 619

Compose中,AlertDialog圆角设置无效,或四角出现白色背景的解决方式

AlertDialog是compose中的一个控件;在使用的过程中,发现对其设置圆角之后未生效,于是探究一番。

LittleFogCat的专栏 我的个人网站:https://xiaoniu.tech 1695
上一篇: AndroidStudio无法查看Compose重组次数?
Halifax ‎
博客等级 码龄14年 4272粉丝 43原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Halifax ‎

交个朋友

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值