Skip to content

Commit 9837721

Browse files
ymarianldjcmu
authored andcommitted
Replace circular border drawable with a drawable for any shape.
PiperOrigin-RevId: 224205053
1 parent cf69538 commit 9837721

File tree

6 files changed

+88
-138
lines changed

6 files changed

+88
-138
lines changed

catalog/java/io/material/catalog/application/theme/res/values/styles.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@
2323
<item name="navigationIcon">@drawable/ic_close_vd_theme_24px</item>
2424
</style>
2525

26-
<style name="Widget.Catalog.FloatingActionButton" parent="Widget.MaterialComponents.FloatingActionButton">
27-
<item name="borderWidth">0dp</item>
28-
</style>
29-
3026
<style name="TextAppearance.Catalog.SectionTitle" parent="TextAppearance.AppCompat.Subhead"/>
3127

3228
<style name="TextAppearance.Catalog.Body" parent="TextAppearance.AppCompat.Body1"/>

catalog/java/io/material/catalog/application/theme/res/values/themes.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,15 @@
2525

2626
<item name="catalogToolbarStyle">@style/Widget.Catalog.Toolbar</item>
2727
<item name="catalogToolbarWithCloseButtonStyle">@style/Widget.Catalog.Toolbar.WithCloseButton</item>
28-
<item name="floatingActionButtonStyle">@style/Widget.Catalog.FloatingActionButton</item>
2928
</style>
3029

3130
<style name="Theme.Catalog.Dark" parent="Theme.MaterialComponents.NoActionBar">
3231
<item name="catalogToolbarStyle">@style/Widget.Catalog.Toolbar</item>
3332
<item name="catalogToolbarWithCloseButtonStyle">@style/Widget.Catalog.Toolbar.WithCloseButton</item>
34-
<item name="floatingActionButtonStyle">@style/Widget.Catalog.FloatingActionButton</item>
3533
</style>
3634

3735
<style name="Theme.Catalog.DayNight" parent="Theme.MaterialComponents.DayNight.NoActionBar">
3836
<item name="catalogToolbarStyle">@style/Widget.Catalog.Toolbar</item>
3937
<item name="catalogToolbarWithCloseButtonStyle">@style/Widget.Catalog.Toolbar.WithCloseButton</item>
40-
<item name="floatingActionButtonStyle">@style/Widget.Catalog.FloatingActionButton</item>
4138
</style>
4239
</resources>

lib/java/com/google/android/material/internal/CircularBorderDrawable.java renamed to lib/java/com/google/android/material/floatingactionbutton/BorderDrawable.java

Lines changed: 81 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2015 The Android Open Source Project
2+
* Copyright (C) 2018 The Android Open Source Project
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,72 +14,96 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.google.android.material.internal;
17+
package com.google.android.material.floatingactionbutton;
1818

1919
import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
2020

21+
import android.annotation.TargetApi;
2122
import android.content.res.ColorStateList;
2223
import android.graphics.Canvas;
2324
import android.graphics.ColorFilter;
2425
import android.graphics.LinearGradient;
26+
import android.graphics.Outline;
2527
import android.graphics.Paint;
28+
import android.graphics.Path;
2629
import android.graphics.PixelFormat;
2730
import android.graphics.Rect;
2831
import android.graphics.RectF;
2932
import android.graphics.Shader;
3033
import android.graphics.drawable.Drawable;
34+
import android.os.Build.VERSION_CODES;
3135
import android.support.annotation.ColorInt;
3236
import android.support.annotation.Dimension;
33-
import android.support.annotation.FloatRange;
3437
import android.support.annotation.IntRange;
3538
import android.support.annotation.NonNull;
36-
import android.support.annotation.Nullable;
3739
import android.support.annotation.RestrictTo;
40+
import com.google.android.material.shape.ShapeAppearanceModel;
41+
import com.google.android.material.shape.ShapeAppearancePathProvider;
3842
import android.support.v4.graphics.ColorUtils;
3943

40-
/** A drawable which draws an oval 'border'. */
44+
/**
45+
* A Drawable that draws borders for {@link FloatingActionButton}
46+
*
47+
* @hide
48+
* */
4149
@RestrictTo(LIBRARY_GROUP)
42-
public class CircularBorderDrawable extends Drawable {
50+
class BorderDrawable extends Drawable {
4351

4452
/**
4553
* We actually draw the stroke wider than the border size given. This is to reduce any potential
4654
* transparent space caused by anti-aliasing and padding rounding. This value defines the
4755
* multiplier used to determine to draw stroke width.
4856
*/
4957
private static final float DRAW_STROKE_WIDTH_MULTIPLE = 1.3333f;
58+
private final ShapeAppearancePathProvider pathProvider = new ShapeAppearancePathProvider();
5059

51-
final Paint paint;
52-
final Rect rect = new Rect();
53-
final RectF rectF = new RectF();
54-
final CircularBorderState state = new CircularBorderState();
60+
private final Paint paint;
61+
private final Path shapePath = new Path();
62+
private final Rect rect = new Rect();
63+
private final RectF rectF = new RectF();
5564

5665
@Dimension float borderWidth;
57-
5866
@ColorInt private int topOuterStrokeColor;
5967
@ColorInt private int topInnerStrokeColor;
6068
@ColorInt private int bottomOuterStrokeColor;
6169
@ColorInt private int bottomInnerStrokeColor;
62-
63-
private ColorStateList borderTint;
6470
@ColorInt private int currentBorderTintColor;
6571

6672
private boolean invalidateShader = true;
73+
private ColorStateList borderTint;
74+
private ShapeAppearanceModel shapeAppearanceModel;
6775

68-
@FloatRange(from = 0, to = 360)
69-
private float rotation;
70-
71-
public CircularBorderDrawable() {
76+
BorderDrawable(ShapeAppearanceModel shapeAppearanceModel) {
77+
this.shapeAppearanceModel = shapeAppearanceModel;
7278
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
7379
paint.setStyle(Paint.Style.STROKE);
7480
}
7581

76-
@Nullable
82+
public void setBorderWidth(@Dimension float width) {
83+
if (borderWidth != width) {
84+
borderWidth = width;
85+
paint.setStrokeWidth(width * DRAW_STROKE_WIDTH_MULTIPLE);
86+
invalidateShader = true;
87+
invalidateSelf();
88+
}
89+
}
90+
91+
void setBorderTint(ColorStateList tint) {
92+
if (tint != null) {
93+
currentBorderTintColor = tint.getColorForState(getState(), currentBorderTintColor);
94+
}
95+
borderTint = tint;
96+
invalidateShader = true;
97+
invalidateSelf();
98+
}
99+
77100
@Override
78-
public ConstantState getConstantState() {
79-
return state;
101+
public void setColorFilter(ColorFilter colorFilter) {
102+
paint.setColorFilter(colorFilter);
103+
invalidateSelf();
80104
}
81105

82-
public void setGradientColors(
106+
void setGradientColors(
83107
@ColorInt int topOuterStrokeColor,
84108
@ColorInt int topInnerStrokeColor,
85109
@ColorInt int bottomOuterStrokeColor,
@@ -90,16 +114,6 @@ public void setGradientColors(
90114
this.bottomInnerStrokeColor = bottomInnerStrokeColor;
91115
}
92116

93-
/** Set the border width */
94-
public void setBorderWidth(@Dimension float width) {
95-
if (borderWidth != width) {
96-
borderWidth = width;
97-
paint.setStrokeWidth(width * DRAW_STROKE_WIDTH_MULTIPLE);
98-
invalidateShader = true;
99-
invalidateSelf();
100-
}
101-
}
102-
103117
@Override
104118
public void draw(Canvas canvas) {
105119
if (invalidateShader) {
@@ -108,49 +122,59 @@ public void draw(Canvas canvas) {
108122
}
109123

110124
final float halfBorderWidth = paint.getStrokeWidth() / 2f;
111-
final RectF rectF = this.rectF;
125+
copyBounds(rect);
126+
rectF.set(rect);
112127

113128
// We need to inset the oval bounds by half the border width. This is because stroke draws
114129
// the center of the border on the dimension. Whereas we want the stroke on the inside.
130+
if (shapeAppearanceModel.isRoundRect()) {
131+
rectF.inset(halfBorderWidth, halfBorderWidth);
132+
canvas.drawRoundRect(rectF, rectF.width() / 2f, rectF.height() / 2f, paint);
133+
return;
134+
}
135+
136+
pathProvider.calculatePath(shapeAppearanceModel, 1f, rectF, shapePath);
137+
canvas.drawPath(shapePath, paint);
138+
}
139+
140+
@TargetApi(VERSION_CODES.LOLLIPOP)
141+
@Override
142+
public void getOutline(@NonNull Outline outline) {
143+
if (shapeAppearanceModel.isRoundRect()) {
144+
float radius = shapeAppearanceModel.getTopLeftCorner().getCornerSize();
145+
outline.setRoundRect(getBounds(), radius);
146+
return;
147+
}
148+
115149
copyBounds(rect);
116150
rectF.set(rect);
117-
rectF.left += halfBorderWidth;
118-
rectF.top += halfBorderWidth;
119-
rectF.right -= halfBorderWidth;
120-
rectF.bottom -= halfBorderWidth;
121-
122-
canvas.save();
123-
canvas.rotate(rotation, rectF.centerX(), rectF.centerY());
124-
// Draw the oval
125-
canvas.drawOval(rectF, paint);
126-
canvas.restore();
151+
pathProvider.calculatePath(shapeAppearanceModel, 1f, rectF, shapePath);
152+
if (shapePath.isConvex()) {
153+
outline.setConvexPath(shapePath);
154+
}
127155
}
128156

129157
@Override
130158
public boolean getPadding(Rect padding) {
131-
final int borderWidth = Math.round(this.borderWidth);
132-
padding.set(borderWidth, borderWidth, borderWidth, borderWidth);
159+
if (shapeAppearanceModel.isRoundRect()) {
160+
final int borderWidth = Math.round(this.borderWidth);
161+
padding.set(borderWidth, borderWidth, borderWidth, borderWidth);
162+
}
133163
return true;
134164
}
135165

136-
@Override
137-
public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
138-
paint.setAlpha(alpha);
139-
invalidateSelf();
166+
public ShapeAppearanceModel getShapeAppearanceModel() {
167+
return shapeAppearanceModel;
140168
}
141169

142-
public void setBorderTint(ColorStateList tint) {
143-
if (tint != null) {
144-
currentBorderTintColor = tint.getColorForState(getState(), currentBorderTintColor);
145-
}
146-
borderTint = tint;
147-
invalidateShader = true;
148-
invalidateSelf();
170+
public void setShapeAppearanceModel(
171+
ShapeAppearanceModel shapeAppearanceModel) {
172+
this.shapeAppearanceModel = shapeAppearanceModel;
149173
}
150174

151175
@Override
152-
public void setColorFilter(ColorFilter colorFilter) {
153-
paint.setColorFilter(colorFilter);
176+
public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
177+
paint.setAlpha(alpha);
154178
invalidateSelf();
155179
}
156180

@@ -159,13 +183,6 @@ public int getOpacity() {
159183
return borderWidth > 0 ? PixelFormat.TRANSLUCENT : PixelFormat.TRANSPARENT;
160184
}
161185

162-
public final void setRotation(float rotation) {
163-
if (rotation != this.rotation) {
164-
this.rotation = rotation;
165-
invalidateSelf();
166-
}
167-
}
168-
169186
@Override
170187
protected void onBoundsChange(Rect bounds) {
171188
invalidateShader = true;
@@ -191,11 +208,6 @@ protected boolean onStateChange(int[] state) {
191208
return invalidateShader;
192209
}
193210

194-
/**
195-
* Creates a vertical {@link LinearGradient}
196-
*
197-
* @return
198-
*/
199211
private Shader createGradientShader() {
200212
final Rect rect = this.rect;
201213
copyBounds(rect);
@@ -225,22 +237,4 @@ private Shader createGradientShader() {
225237
return new LinearGradient(
226238
0, rect.top, 0, rect.bottom, colors, positions, Shader.TileMode.CLAMP);
227239
}
228-
229-
/**
230-
* Dummy implementation of constant state. This drawable doesn't have shared state. Implementing
231-
* so that calls to getConstantState().newDrawable() don't crash on L and M.
232-
*/
233-
private class CircularBorderState extends ConstantState {
234-
235-
@NonNull
236-
@Override
237-
public Drawable newDrawable() {
238-
return CircularBorderDrawable.this;
239-
}
240-
241-
@Override
242-
public int getChangingConfigurations() {
243-
return 0;
244-
}
245-
}
246240
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import com.google.android.material.animation.ImageMatrixProperty;
4444
import com.google.android.material.animation.MatrixEvaluator;
4545
import com.google.android.material.animation.MotionSpec;
46-
import com.google.android.material.internal.CircularBorderDrawable;
4746
import com.google.android.material.internal.StateListAnimator;
4847
import com.google.android.material.ripple.RippleUtils;
4948
import com.google.android.material.shadow.ShadowViewDelegate;
@@ -92,7 +91,7 @@ class FloatingActionButtonImpl {
9291

9392
MaterialShapeDrawable shapeDrawable;
9493
Drawable rippleDrawable;
95-
CircularBorderDrawable borderDrawable;
94+
BorderDrawable borderDrawable;
9695
Drawable contentBackground;
9796

9897
float elevation;
@@ -309,6 +308,10 @@ final void setShapeAppearance(ShapeAppearanceModel shapeAppearance, boolean usin
309308
if (rippleDrawable instanceof MaterialShapeDrawable) {
310309
((MaterialShapeDrawable) rippleDrawable).setShapeAppearanceModel(shapeAppearance);
311310
}
311+
312+
if (borderDrawable != null) {
313+
borderDrawable.setShapeAppearanceModel(shapeAppearance);
314+
}
312315
}
313316

314317
@Nullable
@@ -812,8 +815,5 @@ void updateFromViewRotation() {
812815
if (shapeDrawable != null) {
813816
shapeDrawable.setShadowCompatRotation((int) rotation);
814817
}
815-
if (borderDrawable != null) {
816-
borderDrawable.setRotation(-rotation);
817-
}
818818
}
819819
}

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
import android.os.Build.VERSION_CODES;
3434
import android.support.annotation.NonNull;
3535
import android.support.annotation.RequiresApi;
36-
import com.google.android.material.internal.CircularBorderDrawable;
37-
import com.google.android.material.internal.CircularBorderDrawableLollipop;
3836
import com.google.android.material.ripple.RippleUtils;
3937
import com.google.android.material.shadow.ShadowViewDelegate;
4038
import com.google.android.material.shape.MaterialShapeDrawable;
@@ -208,9 +206,9 @@ boolean requirePreDrawListener() {
208206
return false;
209207
}
210208

211-
CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
209+
BorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
212210
final Context context = view.getContext();
213-
CircularBorderDrawable borderDrawable = new CircularBorderDrawableLollipop();
211+
BorderDrawable borderDrawable = new BorderDrawable(shapeAppearance);
214212
borderDrawable.setGradientColors(
215213
ContextCompat.getColor(context, R.color.design_fab_stroke_top_outer_color),
216214
ContextCompat.getColor(context, R.color.design_fab_stroke_top_inner_color),

lib/java/com/google/android/material/internal/CircularBorderDrawableLollipop.java

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)