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

Compose笔记(二十八)--加水印

        这一节主要了解一下Compose中的加水印,在开发中,有时候我们需要对应用界面做水印效果,水印是指覆盖在应用界面上的半透明标识或图案,通常用于版权声明、内容归属标记或安全防护,Compose中水印效果实现方式,简单总结如下:

场景:
1. 版权保护与内容归属
图片编辑类App在未保存作品上添加 “草稿” 水印;
文档阅读类App在页面显示用户账号或机构名称,防止截图外泄。
2. 安全与保密需求
敏感信息追踪:在内部系统添加包含用户ID、时间戳的动态水印,便于追溯泄露源头。
防截屏保护:部分金融类App通过水印提示 “截屏可能泄露信息”,增强安全警示。
3. 品牌与视觉识别
强化品牌认知:在产品演示界面、宣传材料中添加品牌logo水印,提升曝光度。
区分版本属性:免费版App添加 “试用版” 水印,付费版则隐藏,作为功能区分标识。

栗子:

使用LazyGrid

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp@Composable
fun WatermarkLazyGrid(markText: String,textStyle: TextStyle = TextStyle(fontSize = 14.sp,fontWeight = FontWeight.Normal,color = Color(0.5f, 0.5f, 0.5f, 0.3f)),columns: Int = 3,rows: Int = 5,rotation: Float = -25f,content: @Composable BoxScope.() -> Unit,
) {Box(modifier = Modifier.fillMaxSize()) {content()LazyVerticalGrid(columns = GridCells.Fixed(columns),modifier = Modifier.fillMaxSize().pointerInput(Unit) {awaitPointerEventScope {while (true) {awaitPointerEvent()}}}) {items(columns * rows) { index ->Box(modifier = Modifier.fillMaxSize().graphicsLayer {rotationZ = rotation},contentAlignment = Alignment.Center) {Text(text = markText,style = textStyle,modifier = Modifier.padding(16.dp))}}}}
}调用:WatermarkLazyGrid("HelloWorld") {FixedGridExample()}

 使用Canvas

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.rotate
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.sp@Composable
fun WatermarkOverlay(text: String,alpha: Float = 0.1f,textSize: androidx.compose.ui.unit.TextUnit = 18.sp,angle: Float = 30f,content: @Composable BoxScope.() -> Unit,
) {val textMeasurer = rememberTextMeasurer()Canvas(modifier = Modifier.fillMaxSize()) {val canvasWidth = size.widthval canvasHeight = size.heightval textLayoutResult = textMeasurer.measure(text = text,style = TextStyle(fontSize = textSize, color = Color.Black.copy(alpha = alpha)))val textWidth = textLayoutResult.size.width.toFloat()val textHeight = textLayoutResult.size.height.toFloat()val xStep = textWidth * 2val yStep = textHeight * 2for (x in -canvasWidth.toInt()..canvasWidth.toInt() step xStep.toInt()) {for (y in -canvasHeight.toInt()..canvasHeight.toInt() step yStep.toInt()) {rotate(degrees = angle, pivot = Offset(x.toFloat(), y.toFloat())) {drawText(textMeasurer = textMeasurer,text = text,topLeft = Offset(x.toFloat(), y.toFloat()))}}}}
}

用Modifier.graphicsLayer

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.sp@Composable
fun WatermarkPlay(markText: String,textStyle: TextStyle = TextStyle(fontSize = 14.sp,fontWeight = FontWeight.Normal,color = Color(0.5f, 0.5f, 0.5f, 0.3f)),columns: Int = 3,rows: Int = 5,rotation: Float = -25f,content: @Composable BoxScope.() -> Unit,
) {Box(modifier = Modifier.fillMaxSize()) {content()BoxWithConstraints(modifier = Modifier.fillMaxSize()) {val boxWidth = constraints.maxWidth.toFloat()val boxHeight = constraints.maxHeight.toFloat()val horizontalSpacing = boxWidth / (columns + 1)val verticalSpacing = boxHeight / (rows + 1)for (row in 0 until rows) {for (col in 0 until columns) {val x = horizontalSpacing * (col + 1)val y = verticalSpacing * (row + 1)Text(text = markText,style = textStyle,modifier = Modifier.offset { IntOffset(x.toInt(), y.toInt()) }.graphicsLayer {rotationZ = rotationalpha = 0.3f // 透明度})}}}}
}使用:
WatermarkPlay("HelloWorld") {FixedGridExample()}
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material.Card@Composable
fun FixedGridExample() {val items = List(6) { "Item $it" }LazyVerticalGrid(columns = GridCells.Fixed(3), // 固定3列contentPadding = PaddingValues(20.dp),verticalArrangement = Arrangement.spacedBy(4.dp),horizontalArrangement = Arrangement.spacedBy(12.dp)) {items(items) { item ->Card(onClick = {},modifier = Modifier.height(100.dp)) {Box(contentAlignment = Alignment.Center,modifier = Modifier.fillMaxSize()) {Text(item)}}}}
}

总结:
1. Canvas方案:
    适合复杂图案或高性能需求场景
    需要手动处理文本测量和绘制
2. Modifier方案:
    代码最简洁,利用Compose现有API
    适合简单文本水印场景
3. LazyGrid方案:
    布局最灵活,支持滚动和动态内容
    适合需要响应式布局的场景
    比Canvas和Modifier方案略重

注意:
1 透明度与可读性平衡,水印过深会影响主内容,过浅则起不到作用,建议使用alpha=0.1 ~ 0.2的半透明效果.
2 水印若覆盖在可点击元素上,可能拦截触摸事件,使用pointerInput(Unit) {}让水印层忽略触摸事件.    

http://www.lqws.cn/news/471421.html

相关文章:

  • 【好用但慎用】Windows 系统中将所有 WSL 发行版从 C 盘迁移到 非系统 盘的完整笔记(附 异常处理)
  • 网络基础入门:从OSI模型到TCP/IP协议详解
  • Gartner《AI-Driven Methods for Cost-Efficiency》学习心得
  • SQL Server 数据库操作
  • 大模型的开发应用(十二):RAG 与 LlamaIndex基础
  • 【论文阅读】人工智能在直升机航空电子系统中的应用
  • 随机一道面试题1:Python是解释型语言or编译型语言?
  • 算法-Day04
  • SD-WAN 不是“裸跑”:聊聊怎么把网络安全绑在智能网关上
  • 2025zbrush雕刻笔记
  • DPO直接偏好函数的学习解读
  • C语言:最大公约数
  • 以AI赋能创意未来:即梦3.0与Seedance1.0Lite重磅登陆POE!
  • 操作系统内核态和用户态--2-系统调用是什么?
  • 新手如何利用AI助手Cursor生成复杂项目
  • LINUX621 NFS 同步 ;FTP;samba环境
  • 李宏毅2025《机器学习》第三讲-AI的脑科学
  • AI大模型学习之基础数学:微积分在AI大模型中的核心-梯度与优化(梯度下降)详解
  • FreeRTOS事件组(Event Group)
  • Rust调用 DeepSeek API
  • kibana和elasticsearch安装
  • Docker简单介绍与使用以及下载对应镜像(项目前置)
  • 《揭开CSS渲染的隐秘角落:重排与重绘的深度博弈》
  • 《Whisper:开启语音识别新时代的钥匙》
  • 【Redis】深入理解 Redis 事务:命令、应用与实战案例
  • SiteAzure:解决数据库服务器内存频繁吃满
  • 【Weaviate底层机制】分布式一致性深度解析:Raft算法与最终一致性的协同设计
  • PHP语法基础篇(五):流程控制
  • 给交叉工具链增加libelf.so
  • PowerShell读取CSV并遍历组数组