1+ package love.forte.simbot.codegen.components
2+
3+ import androidx.compose.animation.core.animateFloatAsState
4+ import androidx.compose.foundation.background
5+ import androidx.compose.foundation.layout.Box
6+ import androidx.compose.foundation.layout.fillMaxSize
7+ import androidx.compose.material3.MaterialTheme
8+ import androidx.compose.runtime.Composable
9+ import androidx.compose.runtime.getValue
10+ import androidx.compose.ui.Modifier
11+ import androidx.compose.ui.draw.alpha
12+ import androidx.compose.ui.draw.drawBehind
13+ import androidx.compose.ui.geometry.Offset
14+ import androidx.compose.ui.graphics.*
15+ import androidx.compose.ui.graphics.drawscope.DrawScope
16+ import androidx.compose.ui.graphics.drawscope.clipPath
17+ import androidx.compose.ui.draw.clip
18+ import androidx.compose.ui.geometry.Size
19+ import androidx.compose.ui.geometry.toRect
20+ import kotlin.math.sin
21+ import kotlin.math.cos
22+ import kotlin.math.PI
23+ import kotlin.math.exp
24+ import kotlin.math.sqrt
25+
26+ /* *
27+ * 毛玻璃效果修饰符
28+ * 通过多层半透明背景和纹理模拟毛玻璃效果,无需依赖CSS或DOM
29+ * 现在支持形状裁剪,确保效果不会溢出圆角等边界
30+ *
31+ * @param isActive 是否启用毛玻璃效果
32+ * @param intensity 效果强度,范围0.0-1.0
33+ * @param backgroundColor 基础背景色,如果为null则使用主题色
34+ * @param shape 裁剪形状,如果为null则不进行形状裁剪
35+ */
36+ @Composable
37+ fun Modifier.frostedGlass (
38+ isActive : Boolean ,
39+ intensity : Float = 1.0f,
40+ backgroundColor : Color ? = null,
41+ shape : Shape ? = null
42+ ): Modifier {
43+ val colorScheme = MaterialTheme .colorScheme
44+ val baseColor = backgroundColor ? : colorScheme.surface
45+
46+ // 动画过渡效果强度
47+ val animatedIntensity by animateFloatAsState(
48+ targetValue = if (isActive) intensity else 0f ,
49+ label = " frostedGlassIntensity"
50+ )
51+
52+ return this .then(
53+ if (animatedIntensity > 0f ) {
54+ Modifier .drawBehind {
55+ drawFrostedGlassEffect(
56+ baseColor = baseColor,
57+ primaryColor = colorScheme.primary,
58+ surfaceVariant = colorScheme.surfaceVariant,
59+ intensity = animatedIntensity,
60+ shape = shape
61+ )
62+ }
63+ } else {
64+ Modifier
65+ }
66+ )
67+ }
68+
69+ /* *
70+ * 绘制毛玻璃效果的核心函数
71+ * 通过多层渐变、噪声纹理和透明度变化模拟真实的毛玻璃效果
72+ * 现在支持形状裁剪,确保效果在指定形状内绘制
73+ */
74+ private fun DrawScope.drawFrostedGlassEffect (
75+ baseColor : Color ,
76+ primaryColor : Color ,
77+ surfaceVariant : Color ,
78+ intensity : Float ,
79+ shape : Shape ? = null
80+ ) {
81+ val width = size.width
82+ val height = size.height
83+
84+ // 定义绘制操作的lambda函数
85+ val drawOperations = {
86+ // 第一层:基础半透明背景
87+ drawRect(
88+ color = baseColor.copy(alpha = 0.85f * intensity),
89+ size = size
90+ )
91+
92+ // 第二层:增强的高斯模糊效果,多层渐变模拟真实模糊
93+ drawEnhancedBlurEffect(width, height, intensity, surfaceVariant, primaryColor)
94+
95+ // 第三层:添加纹理噪声,模拟毛玻璃的细微纹理
96+ drawGlassTexture(width, height, intensity, surfaceVariant)
97+
98+ // 第四层:边缘高光效果,增强玻璃质感
99+ drawGlassHighlights(width, height, intensity, primaryColor)
100+ }
101+
102+ // 如果提供了形状,使用裁剪路径绘制;否则直接绘制
103+ if (shape != null ) {
104+ val path = Path ().apply {
105+ addOutline(shape.createOutline(size, layoutDirection, this @drawFrostedGlassEffect))
106+ }
107+ clipPath(path) {
108+ drawOperations()
109+ }
110+ } else {
111+ drawOperations()
112+ }
113+ }
114+
115+ /* *
116+ * 绘制玻璃纹理噪声
117+ * 通过计算生成的伪随机点创建类似磨砂玻璃的纹理效果
118+ * 现在使用增强版本,支持多种大小和透明度的纹理点
119+ */
120+ private fun DrawScope.drawGlassTexture (
121+ width : Float ,
122+ height : Float ,
123+ intensity : Float ,
124+ color : Color
125+ ) {
126+ // 使用增强的纹理点生成算法
127+ val enhancedTexturePoints = generateEnhancedTexturePoints(width, height)
128+
129+ enhancedTexturePoints.forEach { (point, size, alpha) ->
130+ drawCircle(
131+ color = color.copy(alpha = alpha * intensity),
132+ radius = size,
133+ center = point
134+ )
135+ }
136+ }
137+
138+ /* *
139+ * 绘制玻璃高光效果
140+ * 在边缘和特定区域添加微妙的高光,增强玻璃的立体感
141+ */
142+ private fun DrawScope.drawGlassHighlights (
143+ width : Float ,
144+ height : Float ,
145+ intensity : Float ,
146+ highlightColor : Color
147+ ) {
148+ val highlightAlpha = 0.12f * intensity
149+
150+ // 顶部高光
151+ val topHighlight = Brush .verticalGradient(
152+ colors = listOf (
153+ highlightColor.copy(alpha = highlightAlpha),
154+ Color .Transparent
155+ ),
156+ startY = 0f ,
157+ endY = height * 0.3f
158+ )
159+
160+ drawRect(
161+ brush = topHighlight,
162+ size = size
163+ )
164+
165+ // 左侧高光
166+ val leftHighlight = Brush .horizontalGradient(
167+ colors = listOf (
168+ highlightColor.copy(alpha = highlightAlpha * 0.7f ),
169+ Color .Transparent
170+ ),
171+ startX = 0f ,
172+ endX = width * 0.2f
173+ )
174+
175+ drawRect(
176+ brush = leftHighlight,
177+ size = size
178+ )
179+ }
180+
181+ /* *
182+ * 生成纹理点位置
183+ * 使用确定性算法生成看起来随机但可重现的纹理点
184+ */
185+ private fun generateTexturePoints (width : Float , height : Float ): List <Offset > {
186+ val points = mutableListOf<Offset >()
187+ val density = 0.3f // 控制纹理密度
188+ val stepX = width / (width * density / 10 )
189+ val stepY = height / (height * density / 10 )
190+
191+ var x = 0f
192+ while (x < width) {
193+ var y = 0f
194+ while (y < height) {
195+ // 使用三角函数创建伪随机偏移
196+ val offsetX = sin(x * 0.01f + y * 0.007f ) * 3f
197+ val offsetY = cos(y * 0.013f + x * 0.009f ) * 3f
198+
199+ // 只有满足特定条件的点才会被绘制,创建稀疏的纹理效果
200+ if (sin(x * 0.02f ) * cos(y * 0.015f ) > 0.1f ) {
201+ points.add(Offset (x + offsetX, y + offsetY))
202+ }
203+
204+ y + = stepY
205+ }
206+ x + = stepX
207+ }
208+
209+ return points
210+ }
211+
212+ /* *
213+ * 生成增强的纹理点位置
214+ * 返回包含位置、大小和透明度的纹理点,创建更自然的效果
215+ */
216+ private fun generateEnhancedTexturePoints (width : Float , height : Float ): List <Triple <Offset , Float , Float >> {
217+ val points = mutableListOf<Triple <Offset , Float , Float >>()
218+ val density = 0.4f // 增加密度获得更丰富的纹理
219+ val stepX = width / (width * density / 8 )
220+ val stepY = height / (height * density / 8 )
221+
222+ var x = 0f
223+ while (x < width) {
224+ var y = 0f
225+ while (y < height) {
226+ // 使用更复杂的函数创建更自然的分布
227+ val noiseX = sin(x * 0.008f + y * 0.012f ) * 4f
228+ val noiseY = cos(y * 0.011f + x * 0.007f ) * 4f
229+
230+ // 使用多个条件创建不同类型的纹理点
231+ val threshold = sin(x * 0.015f ) * cos(y * 0.018f )
232+ if (threshold > - 0.2f ) {
233+ // 计算点的大小 - 基于位置的变化
234+ val sizeVariation = (sin(x * 0.02f + y * 0.025f ) + 1f ) * 0.5f
235+ val pointSize = 0.3f + sizeVariation * 1.2f
236+
237+ // 计算透明度 - 创建不均匀分布
238+ val alphaVariation = (cos(x * 0.013f + y * 0.019f ) + 1f ) * 0.5f
239+ val pointAlpha = 0.04f + alphaVariation * 0.08f
240+
241+ points.add(
242+ Triple (
243+ Offset (x + noiseX, y + noiseY),
244+ pointSize,
245+ pointAlpha
246+ )
247+ )
248+ }
249+
250+ y + = stepY
251+ }
252+ x + = stepX
253+ }
254+
255+ return points
256+ }
257+
258+ /* *
259+ * 增强的高斯模糊效果
260+ * 通过多层不同半径的渐变叠加,更真实地模拟高斯模糊
261+ */
262+ private fun DrawScope.drawEnhancedBlurEffect (
263+ width : Float ,
264+ height : Float ,
265+ intensity : Float ,
266+ surfaceVariant : Color ,
267+ primaryColor : Color
268+ ) {
269+ // 模拟多层高斯模糊 - 使用多个不同半径的径向渐变
270+ val blurLayers = listOf (
271+ // 大半径,低权重 - 模拟远距离模糊
272+ Triple (width * 1.2f , 0.08f , Offset (width * 0.5f , height * 0.5f )),
273+ // 中等半径,中等权重 - 主要模糊效果
274+ Triple (width * 0.8f , 0.15f , Offset (width * 0.3f , height * 0.2f )),
275+ Triple (width * 0.6f , 0.12f , Offset (width * 0.7f , height * 0.6f )),
276+ // 小半径,高权重 - 细节模糊
277+ Triple (width * 0.4f , 0.2f , Offset (width * 0.2f , height * 0.8f )),
278+ Triple (width * 0.3f , 0.18f , Offset (width * 0.8f , height * 0.3f ))
279+ )
280+
281+ blurLayers.forEach { (radius, weight, center) ->
282+ // 为每层使用轻微不同的颜色,增加真实感
283+ val layerColor = when {
284+ radius > width * 0.8f -> surfaceVariant.copy(alpha = weight * intensity)
285+ radius > width * 0.5f -> primaryColor.copy(alpha = weight * 0.8f * intensity)
286+ else -> surfaceVariant.copy(alpha = weight * 1.2f * intensity)
287+ }
288+
289+ val blurGradient = Brush .radialGradient(
290+ colors = listOf (
291+ layerColor,
292+ layerColor.copy(alpha = layerColor.alpha * 0.7f ),
293+ layerColor.copy(alpha = layerColor.alpha * 0.3f ),
294+ Color .Transparent
295+ ),
296+ center = center,
297+ radius = radius
298+ )
299+
300+ drawRect(
301+ brush = blurGradient,
302+ size = size
303+ )
304+ }
305+ }
306+
307+ /* *
308+ * 毛玻璃容器组件
309+ * 为内容提供毛玻璃背景效果的便捷容器
310+ *
311+ * @param isActive 是否启用毛玻璃效果
312+ * @param intensity 效果强度
313+ * @param modifier 修饰符
314+ * @param content 内容
315+ */
316+ @Composable
317+ fun FrostedGlassContainer (
318+ isActive : Boolean ,
319+ modifier : Modifier = Modifier ,
320+ intensity : Float = 1.0f,
321+ content : @Composable () -> Unit
322+ ) {
323+ Box (
324+ modifier = modifier.frostedGlass(
325+ isActive = isActive,
326+ intensity = intensity
327+ )
328+ ) {
329+ content()
330+ }
331+ }
0 commit comments