1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.compose.modifiers
18
19 import androidx.compose.ui.Modifier
20 import androidx.compose.ui.draw.DrawModifier
21 import androidx.compose.ui.geometry.Size
22 import androidx.compose.ui.graphics.Brush
23 import androidx.compose.ui.graphics.Color
24 import androidx.compose.ui.graphics.Outline
25 import androidx.compose.ui.graphics.RectangleShape
26 import androidx.compose.ui.graphics.Shape
27 import androidx.compose.ui.graphics.SolidColor
28 import androidx.compose.ui.graphics.drawOutline
29 import androidx.compose.ui.graphics.drawscope.ContentDrawScope
30 import androidx.compose.ui.platform.InspectorInfo
31 import androidx.compose.ui.platform.InspectorValueInfo
32 import androidx.compose.ui.platform.debugInspectorInfo
33 import androidx.compose.ui.unit.LayoutDirection
34
35 /**
36 * Draws a fading [shape] with a solid [color] and [alpha] behind the content.
37 *
38 * @param color color to paint background with
39 * @param alpha alpha of the background
40 * @param shape desired shape of the background
41 */
fadingBackgroundnull42 fun Modifier.fadingBackground(color: Color, alpha: () -> Float, shape: Shape = RectangleShape) =
43 this.then(
44 FadingBackground(
45 brush = SolidColor(color),
46 alpha = alpha,
47 shape = shape,
48 inspectorInfo =
49 debugInspectorInfo {
50 name = "background"
51 value = color
52 properties["color"] = color
53 properties["alpha"] = alpha
54 properties["shape"] = shape
55 },
56 )
57 )
58
59 private class FadingBackground
60 constructor(
61 private val brush: Brush,
62 private val shape: Shape,
63 private val alpha: () -> Float,
64 inspectorInfo: InspectorInfo.() -> Unit,
65 ) : DrawModifier, InspectorValueInfo(inspectorInfo) {
66 // naive cache outline calculation if size is the same
67 private var lastSize: Size? = null
68 private var lastLayoutDirection: LayoutDirection? = null
69 private var lastOutline: Outline? = null
70
drawnull71 override fun ContentDrawScope.draw() {
72 if (shape === RectangleShape) {
73 // shortcut to avoid Outline calculation and allocation
74 drawRect()
75 } else {
76 drawOutline()
77 }
78 drawContent()
79 }
80
ContentDrawScopenull81 private fun ContentDrawScope.drawRect() {
82 drawRect(brush, alpha = alpha())
83 }
84
drawOutlinenull85 private fun ContentDrawScope.drawOutline() {
86 val outline =
87 if (size == lastSize && layoutDirection == lastLayoutDirection) {
88 lastOutline!!
89 } else {
90 shape.createOutline(size, layoutDirection, this)
91 }
92 drawOutline(outline, brush = brush, alpha = alpha())
93 lastOutline = outline
94 lastSize = size
95 lastLayoutDirection = layoutDirection
96 }
97
hashCodenull98 override fun hashCode(): Int {
99 var result = brush.hashCode()
100 result = 31 * result + alpha.hashCode()
101 result = 31 * result + shape.hashCode()
102 return result
103 }
104
equalsnull105 override fun equals(other: Any?): Boolean {
106 val otherModifier = other as? FadingBackground ?: return false
107 return brush == otherModifier.brush &&
108 alpha == otherModifier.alpha &&
109 shape == otherModifier.shape
110 }
111
toStringnull112 override fun toString(): String = "FadingBackground(brush=$brush, alpha = $alpha, shape=$shape)"
113 }
114