Jetpack Compose DropdownMenu手指跟随点击显示

目录
  • 引言
  • 效果图
  • 实现方法
    • 1使用DropdownMenu的offset参数
    • 2Modifier.offset
  • 获取到点击的位置
    • Box创建用于监听点击事件修饰符
    • DropdownMenu外层的Box()设置偏移量
  • 完整代码
    • 使用方法

引言

DropdownMenu显示时默认会避开点击的view 通常默认显示在左下方

本篇文章教你实现跟随手指按下位置显示

效果图

实现方法

首先要获取到点击的位置之后计算偏移量

先分析两种offset参数

1使用DropdownMenu的offset参数

获取到点击的位置之后计算偏移量, DropdownMenu的offset参数

@Composable
fun DropdownMenu(
    ...
    offset: DpOffset = DpOffset(0.dp, 0.dp)
    ...
)

这种方法比较麻烦,要反向计算偏移量,因为初始位置(x,y)轴的原点在左下角,而不是左上角

2Modifier.offset

将DropdownMenu嵌套在Box里面,调用BoxD的Modifier.offset()改变DropdownMenu的显示位置
这种方案的的初始位置(x,y)轴的原点在左上角
点击的位置就是DropdownMenu的偏移量,

获取到点击的位置

层级结构

Box{
  card()
  Box{
     DropdownMenu()
  }
}

Box创建用于监听点击事件修饰符

在最外层的Box创建一个用于监听点击事件的修饰符,来捕获点击位置

val animatedOffset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) }
Box(
    modifier = Modifier
        .fillMaxWidth()
        .pointerInput(Unit) {
            coroutineScope {
                while (true) {
                    //获取点击位置
                    val boxOffset = awaitPointerEventScope {
                        awaitFirstDown().position
                    }
                    //显示DropdownMenu
                    expanded = true
                    launch {
                        animatedOffset.animateTo(
                            boxOffset,
                            animationSpec = spring(stiffness = Spring.StiffnessLow)
                        )
                    }
                }
            }
        }
)

DropdownMenu外层的Box()设置偏移量

Box(modifier = Modifier.offset {
    IntOffset(
        animatedOffset.value.x.roundToInt(),
        animatedOffset.value.y.roundToInt()
    )
} ) {
    DropdownMenu()
    }

完整代码

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun FullContent(
    modifier: Modifier,
    context: String
) {
    var expanded by remember { mutableStateOf(false) }
    val animatedOffset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) }
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .pointerInput(Unit) {
                coroutineScope {
                    while (true) {
                        //获取点击位置
                        val boxOffset = awaitPointerEventScope {
                            awaitFirstDown().position
                        }
                        expanded = true
                        launch {
                            animatedOffset.animateTo(
                                boxOffset,
                                animationSpec = spring(stiffness = Spring.StiffnessLow)
                            )
                        }
                    }
                }
            }
    ) {
        Card(modifier = modifier
            .fillMaxWidth(),
            border = BorderStroke(2.dp, CustomTheme.colors.divider)
        ) {
            Text(
                text = context,
                modifier = Modifier.padding(6.dp),
                fontSize = 17.sp,
                fontWeight = FontWeight.Normal,
            )
        }
        Box(modifier = Modifier.offset {
            IntOffset(
                animatedOffset.value.x.roundToInt(),
                animatedOffset.value.y.roundToInt()
            )
        } ) {
            DropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false }
            ) {
                DropdownMenuItem(
                    text = {
                        Text(stringResource(id = R.string.app_copy))
                    },
                    onClick = {
                    })
                DropdownMenuItem(
                    text = {
                        Text(stringResource(id = R.string.app_copy))
                    },
                    onClick = {
                    })
                Divider()
                DropdownMenuItem(
                    text = {
                        Text(stringResource(id = R.string.app_copy))
                    },
                    onClick = {
                    })
            }
        }
    }
}

使用方法

FullContent(
    modifier = Modifier.fillMaxWidth(),
    context = "悄悄的我走了,
正如我悄悄的来;
我挥一挥衣袖,
不带走一片云彩。"
)

以上就是Jetpack Compose DropdownMenu手指跟随点击显示的详细内容,更多关于Jetpack Compose DropdownMenu的资料请关注我们其它相关文章!

时间: 2022-11-14

Jetpack Compose自定义动画与Animatable详解

目录 AnimationSpec 1.spring 2.tween 3.keyframes 4.repeatable 5.snap Animatable 本篇主要是自定义动画与Animatable. AnimationSpec 上一篇中,出现了多次animationSpec属性,它是用来自定义动画规范的.例如: fun Modifier.animateContentSize( animationSpec: FiniteAnimationSpec<IntSize> = spring(), fin

Jetpack Compose 分步指南教程详解

目录 前言 可组合函数 显示简单文本 将样式应用于文本 使用 TextField 进行输入 在 Android Studio 中预览 预览参数 Column Scrollable Column Lazy Column Box Button Card Clickable Image Alert Dialog Material AppBar Material BottomNavigation Material Checkbox Material ProgressBar Material Slider

Jetpack Compose重写TopAppBar实现标题多行折叠详解

目录 前言 MediumTopAppBar 阅读源码 核心 解决方法 重写TopAppBarLayout 完整代码 前言 想用composes实现类似掘金的文章详细页面的标题栏 上滑隐藏标题后标题栏显示标题 compose.material3下的TopAppBar不能嵌套滚动 MediumTopAppBar 便使用了MediumTopAppBar一开始用着没什么问题,但是标题字数多了,MediumTopAppBar就不支持了,最多就两行,进入源码一看就明白了 @ExperimentalMater

Jetpack&nbsp;Compose&nbsp;双指拖拽实现详解

目录 Modifier.offset graphicsLayer Modifier.pointerInput PointerInputScope.detectTransformGestures 逻辑解释 定义4个变量 传入graphicsLayer里面 监听手势 完整代码 效果图 Modifier.offset Compose遇到一个浏览图片的功能,双指放大和缩小 Modifier的offset可以偏移内容.偏移量可以是正的,也可以是非正的.应用偏移只会更改内容的位置,而不会影响其大小测量. o

Jetpack Compose惯性衰减动画AnimateDecay详解

目录 什么是惯性衰减动画 惯性衰减动画 使用要点 block 监听 什么是惯性衰减动画 比如说我们玩微信的时候 手指一拉,微信的列表就会惯性滑动 ,这个滑动的速率当然是越来越慢的,最终停止, 这个其实就是惯性衰减动画的典型例子 那这个例子和animateTo 有啥区别呢? 一个速率变慢的动画 ,听起来似乎 我们用animateTo 设置一些参数也可以实现 其实这里最大的区别就是 animateTo 你是需要设置目标值的,也就是动画结束的那一刻 某个view属性的值 你必须明确指定 而所谓的惯性衰

Android Jetpack Compose开发实用小技巧

目录 前言 实用小技巧 如何移除View点击阴影 Text文本如何垂直居中 如何移除Button的点击阴影 Dialog宽度如何全屏 如何提升编码效率 前言 在Compose开发的过程中,我们会经常遇到一些看起来很简单却不知道如何处理的小问题,比如去除点击阴影.Dialog全屏等问题,本文记录了这些常见小问题的处理方式.如有更好方案欢迎大佬们交流探讨- 实用小技巧 如何移除View点击阴影 这里的View指的是除了Button系列的之外,如Button.TextButton等,也就是自身没有on

Kotlin开发的一些实用小技巧总结

前言 随着Google I/O大会的召开,Google宣布将支持Kotlin作为Android的开发语言,最近关于Kotlin的文章.介绍就异常的活跃. 本文主要给大家介绍了关于Kotlin开发的一些实用小技巧,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 1.Lazy Loading(懒加载) 延迟加载有几个好处.延迟加载能让程序启动时间更快,因为加载被推迟到访问变量时. 这在使用 Kotlin 的 Android 应用程序而不是服务器应用程序中特别有用.对于 Androi

Android实用小技巧之利用Lifecycle写出更好维护的代码

目录 前言 场景 优化版本1 优化版本2 单元测试 总结 前言 你是否在onStart()启动过某项任务却忘记在onStop()中取消呢?人不是机器,难免会有错漏.就算老手不会犯错,也不能保证新人不会.学会下面的小技巧,让这种粗心成为不可能. 关于Lifecycle的源码,已经有很多大佬分析过.这篇文章的主旨是让读者对Lifecycle的使用场景有更多的体会,这样也能更好地理解源码.先来看一个场景,然后一步一步优化. 场景 假设我们有一个界面,模拟一个厨房.里面有灶台和餐桌.要求每秒钟翻炒一下,

JavaScript开发的七个实用小技巧(很有用)

目录 1. 数组求和 2. 使用 length 属性更改数组 3. 数组元素随机打乱 4. 过滤唯一值 5. 逗号运算符 6. 使用数组解构交换数据元素 7. 使用 && 代替 If 条件判断为真的条件 总结 本文译文,采用意译. 下面这些方法对于我来说很有作用,自从我发现了这些操作. 1. 数组求和 假设你有下面的数字数组:let numbers = [2,52,55,5]. 计算求和,我们会想到使用 for,是吧. 但是我们可以使用这行代码完成let sum = numbers.red

Android&nbsp;Jetpack&nbsp;Compose实现列表吸顶效果

目录 stickyHeader 实体类 加载假数据 吸顶标题 二级条目 完整代码 效果图 安卓传统的 Recyclerview 打造悬浮头部StickyHeader的吸顶效果,十分麻烦,而在Compose中就简单多了 stickyHeader Compose设计的时候考虑得很周到,他们提供了stickyHeader 作用就是添加一个粘性标题项,即使在它后面滚动时也会保持固定.标头将保持固定,直到下一个标头取而代之. 参数key - 表示唯一的密钥键. 它不允许对列表出现使用相同的键.密钥的类型应

JavaScript编程的10个实用小技巧

在这篇文章中,我将列出10个Javascript实用小技巧,主要面向Javascript新手和中级开发者.希望每个读者都能至少从中学到一个有用的技巧. 1.变量转换 看起来很简单,但据我所看到的,使用构造函数,像Array()或者Number()来进行变量转换是常用的做法.始终使用原始数据类型(有时也称为字面量)来转换变量,这种没有任何额外的影响的做法反而效率更高. 复制代码 代码如下: var myVar   = "3.14159",str     = ""+ m

总结MySQL建表、查询优化的一些实用小技巧

MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些实用小技巧. 技巧一.数据表冗余记录添加时间与更新时间 我们用到的很多数据表大多情况下都会有表记录的"添加时间(add_time)",我建议大家再新增一个记录"更新时间(update_time)"字段,在我的工作里需要为市场部.运营部等建立各种报表,而很多报表里的数据都是需要到大记录表里去查询的,如果直接查询大表的

jQuery实用小技巧_输入框文字获取和失去焦点的简单实例

jQuery实用小技巧_输入框文字获取和失去焦点的简单实例 <input id="txt" class="text1" type="text" /> <script src="js/jquery-1.7.1.min.js"></script> <script type="text/javascript"> $(function () { $("inp

Java Web十条开发实用小知识

 1.${ctx}与 ${pageContext.request.contextPath}这两个为一个意思,都是获取当前根目录. 不同的是${ctx}为${pageContext.request.contextPath}的简写版,经查证之后果真如此,发现在项目的一个文件内有这样一段话 的配置 复制代码 代码如下: <c:setvar="ctx"value="${pageContext.request.contextPath}"/> 注意在使用${ctx的

提高iOS开发的小技巧和思路小结 (二)

前言 之前跟大家分享过一篇<提高iOS开发的小技巧和思路>,但是里面整理的不够全面,通过最近这段时间的整理学习,又整理了一些小技巧和思路分享给大家,下面话不多说了,来看看详细的介绍吧. 一.如何让你的app在后台持续运行一段时间 iOS的app在按下home键的时候,只有不到五秒钟的时间去处理保存或者是清楚资源的工作,这里提供一种办法.(这是在唐巧的书上面学习的) 产品经理的需求:如果app的本地持久化的额图片超过了100mb,需要去清除. 我之前的做法是在程序启动的时候去做这个事情,很显然效

常用的10个Python实用小技巧

大家好,都说追女孩方法大于态度,学Python也是,今天就给大家分享的是我在用Python编写程序时常用的一些小技巧. 1.多次打印同一个字符 在Python中,不用特地写一个函数来重复打印同一个字符,直接使用Print就可以 tem = 'I Love Python ' print(tem * 3) I Love Python I Love Python I Love Python 2.在函数内部使用生成器 在写Python程序时,我们可以在函数内部直接使用生成器,这样可以使代码更简洁. su