|
16 | 16 |
|
17 | 17 | package com.google.android.material.shape;
|
18 | 18 |
|
| 19 | +import static java.lang.Math.min; |
| 20 | + |
| 21 | +import android.graphics.Matrix; |
| 22 | +import android.graphics.RectF; |
19 | 23 | import android.graphics.drawable.Drawable;
|
| 24 | +import android.graphics.drawable.ShapeDrawable; |
| 25 | +import android.graphics.drawable.shapes.PathShape; |
20 | 26 | import android.view.View;
|
21 | 27 | import androidx.annotation.NonNull;
|
| 28 | +import androidx.annotation.RestrictTo; |
| 29 | +import androidx.annotation.RestrictTo.Scope; |
| 30 | +import androidx.graphics.shapes.RoundedPolygon; |
| 31 | +import androidx.graphics.shapes.Shapes_androidKt; |
22 | 32 | import com.google.android.material.internal.ViewUtils;
|
23 | 33 |
|
24 | 34 | /** Utility methods for {@link MaterialShapeDrawable} and related classes. */
|
@@ -84,4 +94,127 @@ public static void setParentAbsoluteElevation(
|
84 | 94 | materialShapeDrawable.setParentAbsoluteElevation(ViewUtils.getParentAbsoluteElevation(view));
|
85 | 95 | }
|
86 | 96 | }
|
| 97 | + |
| 98 | + /** |
| 99 | + * Returns a {@link ShapeDrawable} with the shape's path. |
| 100 | + * |
| 101 | + * <p>The shape is always assumed to fit in (0, 0) to (1, 1) square. |
| 102 | + * |
| 103 | + * @param shape A {@link RoundedPolygon} object to be used in the drawable. |
| 104 | + * @hide |
| 105 | + */ |
| 106 | + @NonNull |
| 107 | + @RestrictTo(Scope.LIBRARY_GROUP) |
| 108 | + public static ShapeDrawable createShapeDrawable(@NonNull RoundedPolygon shape) { |
| 109 | + PathShape pathShape = new PathShape(Shapes_androidKt.toPath(shape), 1, 1); |
| 110 | + return new ShapeDrawable(pathShape); |
| 111 | + } |
| 112 | + |
| 113 | + /** |
| 114 | + * Creates a new {@link RoundedPolygon}, moving and resizing this one, so it's completely inside |
| 115 | + * the destination bounds. |
| 116 | + * |
| 117 | + * <p>If {@code radial} is true, the shape will be scaled to fit in the biggest circle centered in |
| 118 | + * the destination bounds. This is useful when the shape is animated to rotate around its center. |
| 119 | + * Otherwise, the shape will be scaled to fit in the destination bounds. With either option, the |
| 120 | + * shape's original center will be aligned with the destination bounds center. |
| 121 | + * |
| 122 | + * @param shape The original {@link RoundedPolygon}. |
| 123 | + * @param radial Whether to transform the shape to fit in the biggest circle centered in the |
| 124 | + * destination bounds. |
| 125 | + * @param dstBounds The destination bounds to fit. |
| 126 | + * @return A new {@link RoundedPolygon} that fits in the destination bounds. |
| 127 | + * @hide |
| 128 | + */ |
| 129 | + @NonNull |
| 130 | + @RestrictTo(Scope.LIBRARY_GROUP) |
| 131 | + public static RoundedPolygon normalize( |
| 132 | + @NonNull RoundedPolygon shape, boolean radial, @NonNull RectF dstBounds) { |
| 133 | + float[] srcBoundsArray = new float[4]; |
| 134 | + if (radial) { |
| 135 | + // This calculates the axis-aligned bounds of the shape and returns that rectangle. It |
| 136 | + // determines the max dimension of the shape (by calculating the distance from its center to |
| 137 | + // the start and midpoint of each curve) and returns a square which can be used to hold the |
| 138 | + // object in any rotation. |
| 139 | + shape.calculateMaxBounds(srcBoundsArray); |
| 140 | + } else { |
| 141 | + // This calculates the bounds of the shape without rotating the shape. |
| 142 | + shape.calculateBounds(srcBoundsArray); |
| 143 | + } |
| 144 | + RectF srcBounds = |
| 145 | + new RectF(srcBoundsArray[0], srcBoundsArray[1], srcBoundsArray[2], srcBoundsArray[3]); |
| 146 | + float scale = |
| 147 | + min(dstBounds.width() / srcBounds.width(), dstBounds.height() / srcBounds.height()); |
| 148 | + // Scales the shape with pivot point at its original center then moves it to align its original |
| 149 | + // center with the destination bounds center. |
| 150 | + Matrix transform = createScaleMatrix(scale, scale); |
| 151 | + transform.preTranslate(-srcBounds.centerX(), -srcBounds.centerY()); |
| 152 | + transform.postTranslate(dstBounds.centerX(), dstBounds.centerY()); |
| 153 | + return Shapes_androidKt.transformed(shape, transform); |
| 154 | + } |
| 155 | + |
| 156 | + /** |
| 157 | + * Creates a new {@link RoundedPolygon}, moving and resizing this one, so it's completely inside |
| 158 | + * (0, 0) - (1, 1) square. |
| 159 | + * |
| 160 | + * <p>If {@code radial} is true, the shape will be scaled to fit in the circle centered at (0.5, |
| 161 | + * 0.5) with a radius of 0.5. This is useful when the shape is animated to rotate around its |
| 162 | + * center. Otherwise, the shape will be scaled to fit in the (0, 0) - (1, 1) square. With either |
| 163 | + * option, the shape center will be (0.5, 0.5). |
| 164 | + * |
| 165 | + * @param shape The original {@link RoundedPolygon}. |
| 166 | + * @param radial Whether to transform the shape to fit in the circle centered at (0.5, 0.5) with a |
| 167 | + * radius of 0.5. |
| 168 | + * @return A new {@link RoundedPolygon} that fits in (0, 0) - (1, 1) square. |
| 169 | + * @hide |
| 170 | + */ |
| 171 | + @NonNull |
| 172 | + @RestrictTo(Scope.LIBRARY_GROUP) |
| 173 | + public static RoundedPolygon normalize(@NonNull RoundedPolygon shape, boolean radial) { |
| 174 | + return normalize(shape, radial, new RectF(0, 0, 1, 1)); |
| 175 | + } |
| 176 | + |
| 177 | + /** |
| 178 | + * Returns a {@link Matrix} with the input scales. |
| 179 | + * |
| 180 | + * @param scaleX Scale in X axis. |
| 181 | + * @param scaleY Scale in Y axis |
| 182 | + * @hide |
| 183 | + */ |
| 184 | + @NonNull |
| 185 | + @RestrictTo(Scope.LIBRARY_GROUP) |
| 186 | + static Matrix createScaleMatrix(float scaleX, float scaleY) { |
| 187 | + Matrix matrix = new Matrix(); |
| 188 | + matrix.setScale(scaleX, scaleY); |
| 189 | + return matrix; |
| 190 | + } |
| 191 | + |
| 192 | + /** |
| 193 | + * Returns a {@link Matrix} with the input rotation in degrees. |
| 194 | + * |
| 195 | + * @param degrees The rotation in degrees. |
| 196 | + * @hide |
| 197 | + */ |
| 198 | + @NonNull |
| 199 | + @RestrictTo(Scope.LIBRARY_GROUP) |
| 200 | + static Matrix createRotationMatrix(float degrees) { |
| 201 | + Matrix matrix = new Matrix(); |
| 202 | + matrix.setRotate(degrees); |
| 203 | + return matrix; |
| 204 | + } |
| 205 | + |
| 206 | + /** |
| 207 | + * Returns a {@link Matrix} with the input skews. |
| 208 | + * |
| 209 | + * @param kx The skew in X axis. |
| 210 | + * @param ky The skew in Y axis. |
| 211 | + * @hide |
| 212 | + */ |
| 213 | + @NonNull |
| 214 | + @RestrictTo(Scope.LIBRARY_GROUP) |
| 215 | + static Matrix createSkewMatrix(float kx, float ky) { |
| 216 | + Matrix matrix = new Matrix(); |
| 217 | + matrix.setSkew(kx, ky); |
| 218 | + return matrix; |
| 219 | + } |
87 | 220 | }
|
0 commit comments