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的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Jetpack Compose开发实用小技巧

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

  • Jetpack Compose 双指拖拽实现详解

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

  • 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惯性衰减动画AnimateDecay详解

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

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

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

  • 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 DropdownMenu手指跟随点击显示

    目录 引言 效果图 实现方法 1使用DropdownMenu的offset参数 2Modifier.offset 获取到点击的位置 Box创建用于监听点击事件修饰符 DropdownMenu外层的Box()设置偏移量 完整代码 使用方法 引言 DropdownMenu显示时默认会避开点击的view 通常默认显示在左下方 本篇文章教你实现跟随手指按下位置显示 效果图 实现方法 首先要获取到点击的位置之后计算偏移量 先分析两种offset参数 1使用DropdownMenu的offset参数 获取到

  • 通过Jetpack Compose实现双击点赞动画效果

    目录 实现步骤 先红色画个爱心 点击事件加动画 完整代码 效果图 实现步骤 先红色画个爱心 Icon( Icons.Filled.Favorite, "爱心", Modifier .align(Alignment.Center) tint = Color.Red ) 点击事件加动画 双击监听 .pointerInput(Unit) { detectTapGestures( onDoubleTap = { ... } ) } #### **API 介绍** | API名称 | 作用 |

  • Android Jetpack Compose实现列表吸顶效果

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

  • Jetpack Compose实现列表和动画效果详解

    目录 创建一个列表消息卡片 可交互的动画效果 创建一个列表消息卡片 到目前为止,我们只有一个消息的卡片,看上去有点单调,所以让我们来改善它,让它拥有多条信息.我们需要创建一个能够显示多条消息的函数.对于这种情况,我们可以使用 Compose 的 LazyColumn 和 LazyRow.这些 Composable 只渲染屏幕上可见的元素,所以它们的设计对于长列表来说很有效果.同时,它们避免了 RecyclerView 与 XML 布局的复杂性. import androidx.compose.f

  • 利用Jetpack Compose实现经典俄罗斯方块游戏

    目录 可组合函数 游戏机身 - TetrisBody 游戏按钮 - TetrisButton 游戏屏幕 - TetrisScreen 调度器 - TetrisViewModel 项目地址 你的童年是否有俄罗斯方块呢,本文就来介绍如何通过 Jetpack Compose 实现一个俄罗斯方块 ~~ 先看下效果图,功能还是挺完善的 就我自己的体验来说,使用 Compose 开发的应用我感受不到和 Android 原生开发之间有什么性能差异,但 Compose 在开发难度上会低很多 Google 官网上

  • Jetpack Compose 实现一个图片选择框架功能

    目录 获取图片 拍照策略 NothingCaptureStrategy FileProviderCaptureStrategy MediaStoreCaptureStrategy 总结 拍照权限 取消拍照导致的脏数据 resolveActivity API 的兼容性 File API 的兼容性 Github 知乎的 Matisse应该蛮多 Android 开发者有了解过或者是曾经使用过,这是知乎在 2017 年开源的一个 Android 端图片选择框架,其颜值在现在看来也还是挺不错的 可惜近几年

随机推荐