Skip to content

Commit 53e181b

Browse files
cketchamldjcmu
authored andcommitted
Uncouple CornerSize from CornerTreatment
This allows for more easily updating the CornerSize independently from the CornerTreatment and makes it possible to create different types of CornerSizes such as percentage based corners. However, this means corner sizes can be different depending on the bounds of the shape, so the bounds need to be provided. MaterialShapeDrawable has bounds and the ShapeAppearanceModel, so there are new convenience methods there which return the current corner size for the current bounds of the drawable. PiperOrigin-RevId: 272908508 (cherry picked from commit 0547d2a)
1 parent 6f73b2e commit 53e181b

20 files changed

+686
-245
lines changed

lib/java/com/google/android/material/button/MaterialButtonToggleGroup.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import android.widget.RelativeLayout;
3737
import com.google.android.material.internal.ThemeEnforcement;
3838
import com.google.android.material.internal.ViewUtils;
39+
import com.google.android.material.shape.AbsoluteCornerSize;
40+
import com.google.android.material.shape.CornerSize;
41+
import com.google.android.material.shape.ShapeAppearanceModel;
3942
import java.util.ArrayList;
4043
import java.util.LinkedHashSet;
4144
import java.util.List;
@@ -203,10 +206,10 @@ public void addView(View child, int index, ViewGroup.LayoutParams params) {
203206
ShapeAppearanceModel shapeAppearanceModel = buttonChild.getShapeAppearanceModel();
204207
originalCornerData.add(
205208
new CornerData(
206-
shapeAppearanceModel.getTopLeftCorner().getCornerSize(),
207-
shapeAppearanceModel.getTopRightCorner().getCornerSize(),
208-
shapeAppearanceModel.getBottomRightCorner().getCornerSize(),
209-
shapeAppearanceModel.getBottomLeftCorner().getCornerSize()));
209+
shapeAppearanceModel.getTopLeftCornerSize(),
210+
shapeAppearanceModel.getTopRightCornerSize(),
211+
shapeAppearanceModel.getBottomRightCornerSize(),
212+
shapeAppearanceModel.getBottomLeftCornerSize()));
210213
}
211214

212215
@Override
@@ -491,19 +494,19 @@ private void updateChildShapes() {
491494
// Keeps the left corners of the first child in LTR, or the last child in RTL
492495
shapeAppearanceModelBuilder
493496
.setTopLeftCornerSize(cornerData.topLeft)
494-
.setTopRightCornerSize(0)
495-
.setBottomRightCornerSize(0)
497+
.setTopRightCornerSize(new AbsoluteCornerSize(0))
498+
.setBottomRightCornerSize(new AbsoluteCornerSize(0))
496499
.setBottomLeftCornerSize(cornerData.bottomLeft);
497500
} else if (i != 0 && i < numChildren - 1) {
498501
// Sets corner radii of all middle children to 0
499502
shapeAppearanceModelBuilder.setCornerRadius(0);
500503
} else if (i == (ViewUtils.isLayoutRtl(this) ? 0 : (numChildren - 1))) {
501504
// Keeps the right corners of the last child in LTR, or the first child in RTL
502505
shapeAppearanceModelBuilder
503-
.setTopLeftCornerSize(0)
506+
.setTopLeftCornerSize(new AbsoluteCornerSize(0))
504507
.setTopRightCornerSize(cornerData.topRight)
505508
.setBottomRightCornerSize(cornerData.bottomRight)
506-
.setBottomLeftCornerSize(0);
509+
.setBottomLeftCornerSize(new AbsoluteCornerSize(0));
507510
}
508511
}
509512
button.setShapeAppearanceModel(shapeAppearanceModelBuilder.build());
@@ -620,12 +623,13 @@ public void onPressedChanged(@NonNull MaterialButton button, boolean isPressed)
620623
}
621624

622625
private static class CornerData {
623-
final float topLeft;
624-
final float topRight;
625-
final float bottomRight;
626-
final float bottomLeft;
626+
final CornerSize topLeft;
627+
final CornerSize topRight;
628+
final CornerSize bottomRight;
629+
final CornerSize bottomLeft;
627630

628-
CornerData(float topLeft, float topRight, float bottomRight, float bottomLeft) {
631+
CornerData(
632+
CornerSize topLeft, CornerSize topRight, CornerSize bottomRight, CornerSize bottomLeft) {
629633
this.topLeft = topLeft;
630634
this.topRight = topRight;
631635
this.bottomRight = bottomRight;

lib/java/com/google/android/material/card/MaterialCardViewHelper.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ void setCornerRadius(float cornerRadius) {
280280
}
281281

282282
float getCornerRadius() {
283-
return shapeAppearanceModel.getTopLeftCorner().getCornerSize();
283+
return bgDrawable.getTopLeftCornerResolvedSize();
284284
}
285285

286286
void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
@@ -505,7 +505,7 @@ private float calculateHorizontalBackgroundPadding() {
505505
}
506506

507507
private boolean canClipToOutline() {
508-
return VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && shapeAppearanceModel.isRoundRect();
508+
return VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && bgDrawable.isRoundRect();
509509
}
510510

511511
private float getParentCardViewCalculatedCornerPadding() {
@@ -537,18 +537,25 @@ && canClipToOutline()
537537
private float calculateActualCornerPadding() {
538538
return Math.max(
539539
Math.max(
540-
calculateCornerPaddingForCornerTreatment(shapeAppearanceModel.getTopLeftCorner()),
541-
calculateCornerPaddingForCornerTreatment(shapeAppearanceModel.getTopRightCorner())),
540+
calculateCornerPaddingForCornerTreatment(
541+
shapeAppearanceModel.getTopLeftCorner(), bgDrawable.getTopLeftCornerResolvedSize()),
542+
calculateCornerPaddingForCornerTreatment(
543+
shapeAppearanceModel.getTopRightCorner(),
544+
bgDrawable.getTopRightCornerResolvedSize())),
542545
Math.max(
543-
calculateCornerPaddingForCornerTreatment(shapeAppearanceModel.getBottomRightCorner()),
544-
calculateCornerPaddingForCornerTreatment(shapeAppearanceModel.getBottomLeftCorner())));
546+
calculateCornerPaddingForCornerTreatment(
547+
shapeAppearanceModel.getBottomRightCorner(),
548+
bgDrawable.getBottomRightCornerResolvedSize()),
549+
calculateCornerPaddingForCornerTreatment(
550+
shapeAppearanceModel.getBottomLeftCorner(),
551+
bgDrawable.getBottomLeftCornerResolvedSize())));
545552
}
546553

547-
private float calculateCornerPaddingForCornerTreatment(CornerTreatment treatment) {
554+
private float calculateCornerPaddingForCornerTreatment(CornerTreatment treatment, float size) {
548555
if (treatment instanceof RoundedCornerTreatment) {
549-
return (float) ((1 - COS_45) * treatment.getCornerSize());
556+
return (float) ((1 - COS_45) * size);
550557
} else if (treatment instanceof CutCornerTreatment) {
551-
return treatment.getCornerSize() / 2;
558+
return size / 2;
552559
}
553560
return 0;
554561
}

lib/java/com/google/android/material/chip/ChipDrawable.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,9 +1406,7 @@ public void setChipMinHeight(float chipMinHeight) {
14061406
* @attr ref com.google.android.material.R.styleable#Chip_chipCornerRadius
14071407
*/
14081408
public float getChipCornerRadius() {
1409-
return isShapeThemingEnabled
1410-
? getShapeAppearanceModel().getTopLeftCorner().getCornerSize()
1411-
: chipCornerRadius;
1409+
return isShapeThemingEnabled ? getTopLeftCornerResolvedSize() : chipCornerRadius;
14121410
}
14131411

14141412
/**

lib/java/com/google/android/material/floatingactionbutton/BorderDrawable.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class BorderDrawable extends Drawable {
6363
private final Path shapePath = new Path();
6464
private final Rect rect = new Rect();
6565
private final RectF rectF = new RectF();
66+
private final RectF boundsRectF = new RectF();
6667
private final BorderState state = new BorderState();
6768

6869
@Dimension float borderWidth;
@@ -131,9 +132,10 @@ public void draw(@NonNull Canvas canvas) {
131132

132133
// We need to inset the oval bounds by half the border width. This is because stroke draws
133134
// the center of the border on the dimension. Whereas we want the stroke on the inside.
134-
float cornerSize = shapeAppearanceModel.getTopLeftCorner().getCornerSize();
135+
float cornerSize =
136+
shapeAppearanceModel.getTopLeftCornerSize().getCornerSize(getBoundsAsRectF());
135137
float radius = Math.min(cornerSize, rectF.width() / 2f);
136-
if (shapeAppearanceModel.isRoundRect()) {
138+
if (shapeAppearanceModel.isRoundRect(getBoundsAsRectF())) {
137139
rectF.inset(halfBorderWidth, halfBorderWidth);
138140
canvas.drawRoundRect(rectF, radius, radius, paint);
139141
}
@@ -142,8 +144,8 @@ public void draw(@NonNull Canvas canvas) {
142144
@TargetApi(VERSION_CODES.LOLLIPOP)
143145
@Override
144146
public void getOutline(@NonNull Outline outline) {
145-
if (shapeAppearanceModel.isRoundRect()) {
146-
float radius = shapeAppearanceModel.getTopLeftCorner().getCornerSize();
147+
if (shapeAppearanceModel.isRoundRect(getBoundsAsRectF())) {
148+
float radius = shapeAppearanceModel.getTopLeftCornerSize().getCornerSize(getBoundsAsRectF());
147149
outline.setRoundRect(getBounds(), radius);
148150
return;
149151
}
@@ -158,13 +160,19 @@ public void getOutline(@NonNull Outline outline) {
158160

159161
@Override
160162
public boolean getPadding(@NonNull Rect padding) {
161-
if (shapeAppearanceModel.isRoundRect()) {
163+
if (shapeAppearanceModel.isRoundRect(getBoundsAsRectF())) {
162164
final int borderWidth = Math.round(this.borderWidth);
163165
padding.set(borderWidth, borderWidth, borderWidth, borderWidth);
164166
}
165167
return true;
166168
}
167169

170+
@NonNull
171+
protected RectF getBoundsAsRectF() {
172+
boundsRectF.set(getBounds());
173+
return boundsRectF;
174+
}
175+
168176
public ShapeAppearanceModel getShapeAppearanceModel() {
169177
return shapeAppearanceModel;
170178
}

lib/java/com/google/android/material/floatingactionbutton/ExtendedFloatingActionButton.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
import com.google.android.material.bottomsheet.BottomSheetBehavior;
4949
import com.google.android.material.internal.DescendantOffsetUtils;
5050
import com.google.android.material.internal.ThemeEnforcement;
51+
import com.google.android.material.shape.MaterialShapeDrawable;
52+
import com.google.android.material.shape.ShapeAppearanceModel;
5153
import java.util.List;
5254

5355
/**
@@ -681,10 +683,7 @@ public void set(@NonNull View object, @NonNull Float value) {
681683

682684
@Override
683685
public Float get(@NonNull View object) {
684-
return ((ExtendedFloatingActionButton) object)
685-
.getShapeAppearanceModel()
686-
.getTopRightCorner()
687-
.getCornerSize();
686+
return ((MaterialShapeDrawable) object.getBackground()).getTopRightCornerResolvedSize();
688687
}
689688
};
690689

lib/java/com/google/android/material/floatingactionbutton/FloatingActionButton.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import com.google.android.material.internal.VisibilityAwareImageButton;
7777
import com.google.android.material.resources.MaterialResources;
7878
import com.google.android.material.shadow.ShadowViewDelegate;
79+
import com.google.android.material.shape.AbsoluteCornerSize;
7980
import com.google.android.material.shape.ShapeAppearanceModel;
8081
import com.google.android.material.shape.Shapeable;
8182
import com.google.android.material.stateful.ExtendableSavedState;
@@ -240,7 +241,9 @@ public FloatingActionButton(
240241
MotionSpec hideMotionSpec =
241242
MotionSpec.createFromAttribute(context, a, R.styleable.FloatingActionButton_hideMotionSpec);
242243
ShapeAppearanceModel shapeAppearance =
243-
ShapeAppearanceModel.builder(context, attrs, defStyleAttr, DEF_STYLE_RES, -1).build();
244+
ShapeAppearanceModel.builder(
245+
context, attrs, defStyleAttr, DEF_STYLE_RES, ShapeAppearanceModel.PILL)
246+
.build();
244247

245248
boolean usingDefaultCorner = isUsingDefaultCorner(shapeAppearance);
246249
boolean ensureMinTouchTargetSize = a
@@ -1360,7 +1363,8 @@ public void removeTransformationCallback(
13601363
}
13611364

13621365
private boolean isUsingDefaultCorner(@NonNull ShapeAppearanceModel shapeAppearance) {
1363-
return shapeAppearance.getTopRightCorner().getCornerSize() == -1;
1366+
return ((AbsoluteCornerSize) shapeAppearance.getTopRightCornerSize()).getCornerSize()
1367+
== ShapeAppearanceModel.PILL;
13641368
}
13651369

13661370
class TransformationCallbackWrapper<T extends FloatingActionButton>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2019 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.google.android.material.shape;
18+
19+
import android.graphics.RectF;
20+
import androidx.annotation.NonNull;
21+
import java.util.Arrays;
22+
23+
/** A {@link CornerSize} that always uses the provided size and ignores the bounds. */
24+
public final class AbsoluteCornerSize implements CornerSize {
25+
26+
private final float size;
27+
28+
public AbsoluteCornerSize(float size) {
29+
this.size = size;
30+
}
31+
32+
@Override
33+
public float getCornerSize(@NonNull RectF bounds) {
34+
return size;
35+
}
36+
37+
/**
38+
* Returns the size of this corner. Bounds aren't required since the result is always the same.
39+
*/
40+
public float getCornerSize() {
41+
return size;
42+
}
43+
44+
@Override
45+
public boolean equals(Object o) {
46+
if (this == o) {
47+
return true;
48+
}
49+
if (!(o instanceof AbsoluteCornerSize)) {
50+
return false;
51+
}
52+
AbsoluteCornerSize that = (AbsoluteCornerSize) o;
53+
return size == that.size;
54+
}
55+
56+
@Override
57+
public int hashCode() {
58+
Object[] hashedFields = {size};
59+
return Arrays.hashCode(hashedFields);
60+
}
61+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2019 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.google.android.material.shape;
18+
19+
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20+
21+
import android.graphics.RectF;
22+
import androidx.annotation.NonNull;
23+
import androidx.annotation.RestrictTo;
24+
import java.util.Arrays;
25+
26+
/**
27+
* Adjusts another {@link CornerSize} by some amount.
28+
*
29+
* @hide
30+
*/
31+
@RestrictTo(LIBRARY_GROUP)
32+
public final class AdjustedCornerSize implements CornerSize {
33+
34+
private final CornerSize other;
35+
private final float adjustment;
36+
37+
public AdjustedCornerSize(float adjustment, @NonNull CornerSize other) {
38+
// Rollup other Adjustments into this one
39+
while (other instanceof AdjustedCornerSize) {
40+
other = ((AdjustedCornerSize) other).other;
41+
adjustment += ((AdjustedCornerSize) other).adjustment;
42+
}
43+
44+
this.other = other;
45+
this.adjustment = adjustment;
46+
}
47+
48+
@Override
49+
public float getCornerSize(@NonNull RectF bounds) {
50+
return Math.max(0, other.getCornerSize(bounds) + adjustment);
51+
}
52+
53+
@Override
54+
public boolean equals(Object o) {
55+
if (this == o) {
56+
return true;
57+
}
58+
if (!(o instanceof AdjustedCornerSize)) {
59+
return false;
60+
}
61+
AdjustedCornerSize that = (AdjustedCornerSize) o;
62+
return other.equals(that.other) && adjustment == that.adjustment;
63+
}
64+
65+
@Override
66+
public int hashCode() {
67+
Object[] hashedFields = {other, adjustment};
68+
return Arrays.hashCode(hashedFields);
69+
}
70+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2019 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.google.android.material.shape;
18+
19+
import android.graphics.RectF;
20+
import androidx.annotation.NonNull;
21+
22+
/** Allows clients to describe the size of a corner independently from a {@link CornerTreatment}. */
23+
public interface CornerSize {
24+
/** Returns the corner size that should be used given the full bounds of the shape. */
25+
float getCornerSize(@NonNull RectF bounds);
26+
}

0 commit comments

Comments
 (0)