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 */
backgroundnull42 fun Modifier.background(
43 color: Color,
44 alpha: () -> Float,
45 shape: Shape = RectangleShape,
46 ) =
47 this.then(
48 FadingBackground(
49 brush = SolidColor(color),
50 alpha = alpha,
51 shape = shape,
52 inspectorInfo =
53 debugInspectorInfo {
54 name = "background"
55 value = color
56 properties["color"] = color
57 properties["alpha"] = alpha
58 properties["shape"] = shape
59 }
60 )
61 )
62
63 private class FadingBackground
64 constructor(
65 private val brush: Brush,
66 private val shape: Shape,
67 private val alpha: () -> Float,
68 inspectorInfo: InspectorInfo.() -> Unit
69 ) : DrawModifier, InspectorValueInfo(inspectorInfo) {
70 // naive cache outline calculation if size is the same
71 private var lastSize: Size? = null
72 private var lastLayoutDirection: LayoutDirection? = null
73 private var lastOutline: Outline? = null
74
drawnull75 override fun ContentDrawScope.draw() {
76 if (shape === RectangleShape) {
77 // shortcut to avoid Outline calculation and allocation
78 drawRect()
79 } else {
80 drawOutline()
81 }
82 drawContent()
83 }
84
ContentDrawScopenull85 private fun ContentDrawScope.drawRect() {
86 drawRect(brush, alpha = alpha())
87 }
88
drawOutlinenull89 private fun ContentDrawScope.drawOutline() {
90 val outline =
91 if (size == lastSize && layoutDirection == lastLayoutDirection) {
92 lastOutline!!
93 } else {
94 shape.createOutline(size, layoutDirection, this)
95 }
96 drawOutline(outline, brush = brush, alpha = alpha())
97 lastOutline = outline
98 lastSize = size
99 lastLayoutDirection = layoutDirection
100 }
101
hashCodenull102 override fun hashCode(): Int {
103 var result = brush.hashCode()
104 result = 31 * result + alpha.hashCode()
105 result = 31 * result + shape.hashCode()
106 return result
107 }
108
equalsnull109 override fun equals(other: Any?): Boolean {
110 val otherModifier = other as? FadingBackground ?: return false
111 return brush == otherModifier.brush &&
112 alpha == otherModifier.alpha &&
113 shape == otherModifier.shape
114 }
115
toStringnull116 override fun toString(): String = "FadingBackground(brush=$brush, alpha = $alpha, shape=$shape)"
117 }
118