当前位置: 首页 > news >正文

Compose笔记(四十六)--Popup

         这一节主要了解一下Compose中的Popup,在Jetpack Compose中,Popup是一个用于在当前界面上方显示悬浮内容的组件,类似于原生Android中的PopupWindow。它可以在不影响底层布局的情况下展示临时内容,是实现提示、菜单、气泡等交互元素的核心组件,简单总结:

API
popupPositionProvider
用于计算弹窗相对于锚点的位置,是一个接口,需通过实现类提供位置逻辑,系统会在每次布局或弹窗状态变化时调用此提供者,确保弹窗位置实时更新。
核心方法:calculatePosition(),返回弹窗左上角相对于锚点的像素偏移量(IntOffset)。
onDismissRequest
当用户点击弹窗外部区域或按下返回键时触发,必须实现(否则弹窗可能无法关闭),通常用于将弹窗状态设为false。
properties
弹窗的附加属性,常用配置:
focusable:是否允许弹窗获取焦点(默认false,设为true可在弹窗显示时阻止底层组件交互)。
dismissOnBackPress:是否允许按返回键关闭(默认 true)。
dismissOnClickOutside:是否允许点击外部关闭(默认 true)。
content
弹窗内的内容,通常是Surface、Card等包裹的文本、图标或按钮组合。

场景
1 提示信息,如操作成功/失败的临时提示、表单输入的错误提示等,通常几秒后自动消失。
2 快捷操作菜单,点击图标(如右上角「更多」图标)后显示的操作菜单,类似下拉菜单。
3 气泡提示,长按或悬停在组件上时显示的解释性文字。
4 上下文菜单,长按列表项时显示的与该条目相关的操作(如编辑、删除)。
5 轻量选择器,如日期、时间的简易选择弹窗,无需跳转新页面。

栗子:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.compose.ui.window.PopupProperties@Composable
fun PopupDemo() {var showPopup by remember { mutableStateOf(false) }val density = LocalDensity.currentval positionProvider = object : PopupPositionProvider {override fun calculatePosition(anchorBounds: IntRect,windowSize: IntSize,layoutDirection: androidx.compose.ui.unit.LayoutDirection,popupContentSize: IntSize): IntOffset {return with(density) {IntOffset(x = anchorBounds.left,y = anchorBounds.bottom + 8.dp.roundToPx() )}}}Column(modifier = Modifier.fillMaxSize().padding(20.dp),horizontalAlignment = Alignment.CenterHorizontally,verticalArrangement = Arrangement.Center) {Text(text = "提示弹窗示例",style = MaterialTheme.typography.titleMedium,modifier = Modifier.padding(bottom = 20.dp))Button(onClick = { showPopup = !showPopup }) {Text(if (showPopup) "隐藏提示" else "显示提示")}if (showPopup) {Popup(popupPositionProvider = positionProvider,onDismissRequest = { showPopup = false }, properties = PopupProperties(focusable = false)) {Surface(color = Color(0xFFE3F2FD),shape = MaterialTheme.shapes.small,) {Text(text = "这是一个提示信息",modifier = Modifier.padding(12.dp),color = Color(0xFF0D47A1))}}}}
}
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.compose.ui.window.PopupProperties@Composable
fun PopupDemo() {var showMenu by remember { mutableStateOf(false) }val density = LocalDensity.currentval positionProvider = object : PopupPositionProvider {override fun calculatePosition(anchorBounds: IntRect,windowSize: IntSize,layoutDirection: androidx.compose.ui.unit.LayoutDirection,popupContentSize: IntSize): IntOffset {return with(density) {IntOffset(x = anchorBounds.right - popupContentSize.width,y = anchorBounds.top + 8.dp.roundToPx() )}}}Column(modifier = Modifier.fillMaxSize().padding(20.dp),horizontalAlignment = Alignment.CenterHorizontally,verticalArrangement = Arrangement.Center) {Text(text = "操作菜单弹窗Demo",style = MaterialTheme.typography.titleMedium,modifier = Modifier.padding(bottom = 20.dp))Box(modifier = Modifier.size(48.dp)) {IconButton(onClick = { showMenu = !showMenu }) {Icon(imageVector = Icons.Default.MoreVert,contentDescription = "更多操作")}if (showMenu) {Popup(popupPositionProvider = positionProvider,onDismissRequest = { showMenu = false },properties = PopupProperties(focusable = true)) {Surface(modifier = Modifier.wrapContentSize(),shape = MaterialTheme.shapes.small,) {Column {Box(modifier = Modifier.fillMaxWidth().clickable {showMenu = false}.padding(12.dp)) {Text("复制")}Box(modifier = Modifier.fillMaxWidth().clickable {showMenu = false}.padding(12.dp)) {Text("分享")}Box(modifier = Modifier.fillMaxWidth().clickable {showMenu = false}.padding(12.dp)) {Text("删除", color = Color(0xFFD32F2F))}}}}}}}
}

注意
1 动态定位:popupPositionProvider需处理屏幕边界,避免弹窗被截断。
2 状态管理:确保onDismissRequest 正确更新弹窗状态,防止内存泄漏。
3 性能优化:避免在Popup内容中频繁重组。
4 处理焦点与交互冲突:若弹窗包含可点击元素,需将properties=PopupProperties(focusable=true),否则点击可能穿透到底层组件。底层组件需避免在弹窗显示时响应点击

http://www.dtcms.com/a/336525.html

相关文章:

  • Houdini 粒子学习笔记
  • 服装外贸管理软件 全流程优化解决方案
  • 学习记录(二十)-Overleaf如何插入参考文献
  • Chrome 插件开发实战:从入门到上架的全流程指南
  • 最长回文子串问题:Go语言实现及复杂度分析
  • 63.不同路径
  • Django前后端交互实现用户登录功能
  • 计算机网络---跳板机与堡垒机
  • Centos 更新/修改宝塔版本
  • 第七十八章:AI的“智能美食家”:输出图像风格偏移的定位方法——从“滤镜病”到“大师风范”!
  • 点云的PFH 和 FPFH特征
  • k8sday09
  • C# 反射和特性(自定义特性)
  • 股票术语:“支撑位”
  • 解码词嵌入向量的正负奥秘
  • 一张图总结 - AI代理上下文工程:构建Manus的经验教训
  • Python多线程、锁、多进程、异步编程
  • Linux | i.MX6ULL网络通信-套字节 TCP(第十七章)
  • 【k8s】Kubernetes核心概念与架构详解
  • 4.8 Vue 3: provide / inject 详解
  • LEA(Load Effective Address)指令
  • MACS2简介
  • 欠拟合和过拟合的特征标志,有什么方法解决,又该如何避免
  • 评测系统构建
  • 20.LeNet
  • [逆向知识] AST抽象语法树:混淆与反混淆的逻辑互换(二)
  • 2001-2024年中国玉米种植分布数据集
  • Cesium学习(二)-地形可视化处理
  • AutoSar BSW介绍
  • PyTorch 面试题及详细答案120题(01-05)-- 基础概念与安装