1 /*
2 * Copyright 2020 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 androidx.compose.foundation.shape
18
19 import androidx.annotation.IntRange
20 import androidx.compose.ui.geometry.CornerRadius
21 import androidx.compose.ui.geometry.RoundRect
22 import androidx.compose.ui.geometry.Size
23 import androidx.compose.ui.geometry.toRect
24 import androidx.compose.ui.graphics.Outline
25 import androidx.compose.ui.graphics.Shape
26 import androidx.compose.ui.unit.Dp
27 import androidx.compose.ui.unit.LayoutDirection
28 import androidx.compose.ui.unit.LayoutDirection.Ltr
29 import androidx.compose.ui.unit.dp
30
31 /**
32 * A shape describing the rectangle with rounded corners.
33 *
34 * This shape will automatically mirror the corner sizes in [LayoutDirection.Rtl], use
35 * [AbsoluteRoundedCornerShape] for the layout direction unaware version of this shape.
36 *
37 * @param topStart a size of the top start corner
38 * @param topEnd a size of the top end corner
39 * @param bottomEnd a size of the bottom end corner
40 * @param bottomStart a size of the bottom start corner
41 */
42 class RoundedCornerShape(
43 topStart: CornerSize,
44 topEnd: CornerSize,
45 bottomEnd: CornerSize,
46 bottomStart: CornerSize
47 ) :
48 CornerBasedShape(
49 topStart = topStart,
50 topEnd = topEnd,
51 bottomEnd = bottomEnd,
52 bottomStart = bottomStart
53 ) {
54
createOutlinenull55 override fun createOutline(
56 size: Size,
57 topStart: Float,
58 topEnd: Float,
59 bottomEnd: Float,
60 bottomStart: Float,
61 layoutDirection: LayoutDirection
62 ) =
63 if (topStart + topEnd + bottomEnd + bottomStart == 0.0f) {
64 Outline.Rectangle(size.toRect())
65 } else {
66 Outline.Rounded(
67 RoundRect(
68 rect = size.toRect(),
69 topLeft = CornerRadius(if (layoutDirection == Ltr) topStart else topEnd),
70 topRight = CornerRadius(if (layoutDirection == Ltr) topEnd else topStart),
71 bottomRight =
72 CornerRadius(if (layoutDirection == Ltr) bottomEnd else bottomStart),
73 bottomLeft =
74 CornerRadius(if (layoutDirection == Ltr) bottomStart else bottomEnd)
75 )
76 )
77 }
78
copynull79 override fun copy(
80 topStart: CornerSize,
81 topEnd: CornerSize,
82 bottomEnd: CornerSize,
83 bottomStart: CornerSize
84 ) =
85 RoundedCornerShape(
86 topStart = topStart,
87 topEnd = topEnd,
88 bottomEnd = bottomEnd,
89 bottomStart = bottomStart
90 )
91
92 override fun toString(): String {
93 return "RoundedCornerShape(topStart = $topStart, topEnd = $topEnd, bottomEnd = " +
94 "$bottomEnd, bottomStart = $bottomStart)"
95 }
96
equalsnull97 override fun equals(other: Any?): Boolean {
98 if (this === other) return true
99 if (other !is RoundedCornerShape) return false
100
101 if (topStart != other.topStart) return false
102 if (topEnd != other.topEnd) return false
103 if (bottomEnd != other.bottomEnd) return false
104 if (bottomStart != other.bottomStart) return false
105
106 return true
107 }
108
hashCodenull109 override fun hashCode(): Int {
110 var result = topStart.hashCode()
111 result = 31 * result + topEnd.hashCode()
112 result = 31 * result + bottomEnd.hashCode()
113 result = 31 * result + bottomStart.hashCode()
114 return result
115 }
116 }
117
118 /** Circular [Shape] with all the corners sized as the 50 percent of the shape size. */
119 val CircleShape = RoundedCornerShape(50)
120
121 /**
122 * Creates [RoundedCornerShape] with the same size applied for all four corners.
123 *
124 * @param corner [CornerSize] to apply.
125 */
RoundedCornerShapenull126 fun RoundedCornerShape(corner: CornerSize) = RoundedCornerShape(corner, corner, corner, corner)
127
128 /**
129 * Creates [RoundedCornerShape] with the same size applied for all four corners.
130 *
131 * @param size Size in [Dp] to apply.
132 */
133 fun RoundedCornerShape(size: Dp) = RoundedCornerShape(CornerSize(size))
134
135 /**
136 * Creates [RoundedCornerShape] with the same size applied for all four corners.
137 *
138 * @param size Size in pixels to apply.
139 */
140 fun RoundedCornerShape(size: Float) = RoundedCornerShape(CornerSize(size))
141
142 /**
143 * Creates [RoundedCornerShape] with the same size applied for all four corners.
144 *
145 * @param percent Size in percents to apply.
146 */
147 fun RoundedCornerShape(percent: Int) = RoundedCornerShape(CornerSize(percent))
148
149 /** Creates [RoundedCornerShape] with sizes defined in [Dp]. */
150 fun RoundedCornerShape(
151 topStart: Dp = 0.dp,
152 topEnd: Dp = 0.dp,
153 bottomEnd: Dp = 0.dp,
154 bottomStart: Dp = 0.dp
155 ) =
156 RoundedCornerShape(
157 topStart = CornerSize(topStart),
158 topEnd = CornerSize(topEnd),
159 bottomEnd = CornerSize(bottomEnd),
160 bottomStart = CornerSize(bottomStart)
161 )
162
163 /** Creates [RoundedCornerShape] with sizes defined in pixels. */
164 fun RoundedCornerShape(
165 topStart: Float = 0.0f,
166 topEnd: Float = 0.0f,
167 bottomEnd: Float = 0.0f,
168 bottomStart: Float = 0.0f
169 ) =
170 RoundedCornerShape(
171 topStart = CornerSize(topStart),
172 topEnd = CornerSize(topEnd),
173 bottomEnd = CornerSize(bottomEnd),
174 bottomStart = CornerSize(bottomStart)
175 )
176
177 /**
178 * Creates [RoundedCornerShape] with sizes defined in percents of the shape's smaller side.
179 *
180 * @param topStartPercent The top start corner radius as a percentage of the smaller side, with a
181 * range of 0 - 100.
182 * @param topEndPercent The top end corner radius as a percentage of the smaller side, with a range
183 * of 0 - 100.
184 * @param bottomEndPercent The bottom end corner radius as a percentage of the smaller side, with a
185 * range of 0 - 100.
186 * @param bottomStartPercent The bottom start corner radius as a percentage of the smaller side,
187 * with a range of 0 - 100.
188 */
189 fun RoundedCornerShape(
190 @IntRange(from = 0, to = 100) topStartPercent: Int = 0,
191 @IntRange(from = 0, to = 100) topEndPercent: Int = 0,
192 @IntRange(from = 0, to = 100) bottomEndPercent: Int = 0,
193 @IntRange(from = 0, to = 100) bottomStartPercent: Int = 0
194 ) =
195 RoundedCornerShape(
196 topStart = CornerSize(topStartPercent),
197 topEnd = CornerSize(topEndPercent),
198 bottomEnd = CornerSize(bottomEndPercent),
199 bottomStart = CornerSize(bottomStartPercent)
200 )
201