Skip to content

Commit

Permalink
Add support for percentages to ShapeAppearanceModel
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 272946740
(cherry picked from commit a130a0c)
  • Loading branch information
cketcham authored and ldjcmu committed Oct 4, 2019
1 parent 5ff7b35 commit c831ecc
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@
</style>

<style name="ShapeAppearanceOverlay.MaterialComponents.Chip" parent="">
<!-- Replace with 50% -->
<item name="cornerSize">16dp</item>
<item name="cornerSize">50%</item>
</style>

<!-- Style for Chips that appear in text fields as a span.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,6 @@ AnimatorSet createAnimator(@NonNull MotionSpec spec) {
animators.add(spec.getAnimator("height", fab, ExtendedFloatingActionButton.HEIGHT));
}

if (spec.hasPropertyValues("cornerRadius") && fab.isUsingPillCorner()) {
animators
.add(spec.getAnimator("cornerRadius", fab, ExtendedFloatingActionButton.CORNER_RADIUS));
}

AnimatorSet set = new AnimatorSet();
AnimatorSetCompat.playTogether(set, animators);
return set;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.RectF;
import androidx.annotation.AnimatorRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand All @@ -48,7 +49,7 @@
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.internal.DescendantOffsetUtils;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.shape.MaterialShapeDrawable;
import com.google.android.material.shape.CornerSize;
import com.google.android.material.shape.ShapeAppearanceModel;
import java.util.List;

Expand Down Expand Up @@ -89,7 +90,6 @@ public class ExtendedFloatingActionButton extends MaterialButton implements Atta
@NonNull private final Behavior<ExtendedFloatingActionButton> behavior;

private boolean isExtended = true;
private boolean isUsingPillCorner = true;

/**
* Callback to be invoked when the visibility or the state of an ExtendedFloatingActionButton
Expand Down Expand Up @@ -200,7 +200,17 @@ public int getHeight() {

ShapeAppearanceModel shapeAppearanceModel =
ShapeAppearanceModel.builder(
context, attrs, defStyleAttr, DEF_STYLE_RES, ShapeAppearanceModel.PILL)
context,
attrs,
defStyleAttr,
DEF_STYLE_RES,
// TODO(b/121352029): Use ShapeAppearanceModel.PILL once this bug is fixed.
new CornerSize() {
@Override
public float getCornerSize(@NonNull RectF bounds) {
return getAdjustedRadius((int) bounds.height());
}
})
.build();
setShapeAppearanceModel(shapeAppearanceModel);
}
Expand All @@ -215,45 +225,12 @@ protected void onAttachedToWindow() {
}
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

if (isUsingPillCorner) {
setShapeAppearanceModel(createPillCornerShapeAppearance());
}
}

@NonNull
@Override
public Behavior<ExtendedFloatingActionButton> getBehavior() {
return behavior;
}

@Override
public void setShapeAppearanceModel(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
if (shapeAppearanceModel.isUsingPillCorner()) {
isUsingPillCorner = true;
shapeAppearanceModel = createPillCornerShapeAppearance();
}
super.setShapeAppearanceModel(shapeAppearanceModel);
}

@NonNull
private ShapeAppearanceModel createPillCornerShapeAppearance() {
return getShapeAppearanceModel().withCornerRadius(getAdjustedRadius(getMeasuredHeight()));
}

@Override
public void setCornerRadius(int cornerRadius) {
isUsingPillCorner = cornerRadius == ShapeAppearanceModel.PILL;
if (isUsingPillCorner) {
cornerRadius = getAdjustedRadius(getMeasuredHeight());
} else if (cornerRadius < 0) {
cornerRadius = 0;
}
super.setCornerRadius(cornerRadius);
}

/**
* Extends or shrinks the fab depending on the value of {@param extended}.
Expand Down Expand Up @@ -554,10 +531,6 @@ public void setShrinkMotionSpecResource(@AnimatorRes int id) {
setShrinkMotionSpec(MotionSpec.createFromResource(getContext(), id));
}

boolean isUsingPillCorner() {
return isUsingPillCorner;
}

private void performMotion(
@NonNull final MotionStrategy strategy, @Nullable final OnChangedCallback callback) {
if (strategy.shouldCancel()) {
Expand Down Expand Up @@ -667,26 +640,6 @@ public Float get(@NonNull View object) {
}
};

/**
* A Property wrapper around the <code>cornerRadius</code> functionality handled by the {@link
* ExtendedFloatingActionButton#setCornerRadius(int)} and {@link
* ExtendedFloatingActionButton#getCornerRadius()} methods.
*/
static final Property<View, Float> CORNER_RADIUS =
new Property<View, Float>(Float.class, "cornerRadius") {
@Override
public void set(@NonNull View object, @NonNull Float value) {
ExtendedFloatingActionButton efab = ((ExtendedFloatingActionButton) object);
efab.setShapeAppearanceModel(
efab.getShapeAppearanceModel().withCornerRadius(value.intValue()));
}

@Override
public Float get(@NonNull View object) {
return ((MaterialShapeDrawable) object.getBackground()).getTopRightCornerResolvedSize();
}
};

/**
* Returns an adjusted radius value that corrects any rounding errors.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@
import com.google.android.material.internal.VisibilityAwareImageButton;
import com.google.android.material.resources.MaterialResources;
import com.google.android.material.shadow.ShadowViewDelegate;
import com.google.android.material.shape.AbsoluteCornerSize;
import com.google.android.material.shape.ShapeAppearanceModel;
import com.google.android.material.shape.Shapeable;
import com.google.android.material.stateful.ExtendableSavedState;
Expand Down Expand Up @@ -245,7 +244,6 @@ public FloatingActionButton(
context, attrs, defStyleAttr, DEF_STYLE_RES, ShapeAppearanceModel.PILL)
.build();

boolean usingDefaultCorner = isUsingDefaultCorner(shapeAppearance);
boolean ensureMinTouchTargetSize = a
.getBoolean(R.styleable.FloatingActionButton_ensureMinTouchTargetSize, false);

Expand All @@ -256,7 +254,7 @@ public FloatingActionButton(

expandableWidgetHelper = new ExpandableWidgetHelper(this);

getImpl().setShapeAppearance(shapeAppearance, usingDefaultCorner);
getImpl().setShapeAppearance(shapeAppearance);
getImpl()
.initializeBackgroundDrawable(backgroundTint, backgroundTintMode, rippleColor, borderWidth);
getImpl().setMinTouchTargetSize(minTouchTargetSize);
Expand Down Expand Up @@ -522,7 +520,7 @@ public void setImageDrawable(@Nullable Drawable drawable) {
/** Sets the {@link ShapeAppearanceModel} for this {@link FloatingActionButton}. */
@Override
public void setShapeAppearanceModel(@NonNull ShapeAppearanceModel shapeAppearance) {
getImpl().setShapeAppearance(shapeAppearance, isUsingDefaultCorner(shapeAppearance));
getImpl().setShapeAppearance(shapeAppearance);
}

/** Returns the {@link ShapeAppearanceModel} for this {@link FloatingActionButton}. */
Expand Down Expand Up @@ -691,7 +689,6 @@ public void setSize(@Size int size) {
customSize = NO_CUSTOM_SIZE;
if (size != this.size) {
this.size = size;
getImpl().updateSize();
requestLayout();
}
}
Expand Down Expand Up @@ -752,7 +749,6 @@ public void setCustomSize(@Px int size) {

if (size != customSize) {
customSize = size;
getImpl().updateSize();
requestLayout();
}
}
Expand Down Expand Up @@ -1362,11 +1358,6 @@ public void removeTransformationCallback(
getImpl().removeTransformationCallback(new TransformationCallbackWrapper(listener));
}

private boolean isUsingDefaultCorner(@NonNull ShapeAppearanceModel shapeAppearance) {
return ((AbsoluteCornerSize) shapeAppearance.getTopRightCornerSize()).getCornerSize()
== ShapeAppearanceModel.PILL;
}

class TransformationCallbackWrapper<T extends FloatingActionButton>
implements InternalTransformationCallback {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ class FloatingActionButtonImpl {
@Nullable BorderDrawable borderDrawable;
@Nullable Drawable contentBackground;

boolean usingDefaultCorner;
boolean ensureMinTouchTargetSize;
boolean shadowPaddingEnabled = true;
float elevation;
Expand Down Expand Up @@ -305,14 +304,8 @@ private void calculateImageMatrixFromScale(float scale, @NonNull Matrix matrix)
}
}

final void setShapeAppearance(
@NonNull ShapeAppearanceModel shapeAppearance, boolean usingDefaultCorner) {
if (usingDefaultCorner) {
shapeAppearance = shapeAppearance.withCornerRadius(view.getSizeDimension() / 2);
}

final void setShapeAppearance(@NonNull ShapeAppearanceModel shapeAppearance) {
this.shapeAppearance = shapeAppearance;
this.usingDefaultCorner = usingDefaultCorner;
if (shapeDrawable != null) {
shapeDrawable.setShapeAppearanceModel(shapeAppearance);
}
Expand Down Expand Up @@ -645,16 +638,6 @@ void onCompatShadowChanged() {
// Ignore pre-v21
}

void updateSize() {
if (!usingDefaultCorner || shapeDrawable == null || shapeAppearance == null) {
// Leave shape appearance as is.
return;
}

setShapeAppearance(
shapeAppearance.withCornerRadius(view.getSizeDimension() / 2f), usingDefaultCorner);
}

final void updatePadding() {
Rect rect = tmpRect;
getPadding(rect);
Expand Down Expand Up @@ -736,9 +719,6 @@ public boolean onPreDraw() {

MaterialShapeDrawable createShapeDrawable() {
ShapeAppearanceModel shapeAppearance = checkNotNull(this.shapeAppearance);
if (usingDefaultCorner) {
shapeAppearance = shapeAppearance.withCornerRadius(view.getSizeDimension() / 2f);
}
return new MaterialShapeDrawable(shapeAppearance);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,6 @@ BorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTi
@Override
MaterialShapeDrawable createShapeDrawable() {
ShapeAppearanceModel shapeAppearance = checkNotNull(this.shapeAppearance);
if (usingDefaultCorner) {
shapeAppearance = shapeAppearance.withCornerRadius(view.getSizeDimension() / 2f);
}
return new AlwaysStatefulMaterialShapeDrawable(shapeAppearance);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@
</style>

<style name="ShapeAppearanceOverlay.MaterialComponents.FloatingActionButton" parent="">
<!-- use @null to change to 50% programmatically. -->
<item name="cornerSize">@null</item>
<item name="cornerSize">50%</item>
</style>

<style name="Widget.MaterialComponents.ExtendedFloatingActionButton" parent="Widget.MaterialComponents.Button">
Expand Down Expand Up @@ -82,10 +81,15 @@
<item name="iconTint">@color/mtrl_extended_fab_text_color_selector</item>
<item name="rippleColor">@color/mtrl_extended_fab_ripple_color</item>
<item name="shapeAppearanceOverlay">
@style/ShapeAppearanceOverlay.MaterialComponents.FloatingActionButton
@style/ShapeAppearanceOverlay.MaterialComponents.ExtendedFloatingActionButton
</item>
</style>

<style name="ShapeAppearanceOverlay.MaterialComponents.ExtendedFloatingActionButton" parent="">
<!-- TODO(b/121352029): ExtendedFloatingActionButton adds 1px to the height -->
<item name="cornerSize">@null</item>
</style>

<style name="Widget.MaterialComponents.ExtendedFloatingActionButton.Icon" parent="Widget.MaterialComponents.ExtendedFloatingActionButton">
<item name="android:gravity">start|center_vertical</item>
<item name="android:paddingStart" tools:ignore="NewApi">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.google.android.material.color.MaterialColors;
import com.google.android.material.elevation.ElevationOverlayProvider;
import com.google.android.material.shadow.ShadowRenderer;
import com.google.android.material.shape.ShapeAppearanceModel.CornerSizeUnaryOperator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

Expand Down Expand Up @@ -1096,7 +1097,20 @@ protected final void calculatePathForSize(@NonNull RectF bounds, @NonNull Path p
private void calculateStrokePath() {
// Adjust corner radius in order to draw the stroke so that the corners of the background are
// drawn on top of the edges.
strokeShapeAppearance = getShapeAppearanceModel().withAdjustedCorners(-getStrokeInsetLength());
strokeShapeAppearance =
getShapeAppearanceModel()
.withTransformedCornerSizes(
new CornerSizeUnaryOperator() {
@NonNull
@Override
public CornerSize apply(@NonNull CornerSize cornerSize) {
// Don't adjust for relative corners they will change by themselves when the
// bounds change.
return cornerSize instanceof RelativeCornerSize
? cornerSize
: new AdjustedCornerSize(-getStrokeInsetLength(), cornerSize);
}
});

pathProvider.calculatePath(
strokeShapeAppearance,
Expand Down
62 changes: 62 additions & 0 deletions lib/java/com/google/android/material/shape/RelativeCornerSize.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.material.shape;

import android.graphics.RectF;
import androidx.annotation.NonNull;
import java.util.Arrays;

/**
* A {@link CornerSize} that takes a percent and computes the size used based on the height of the
* shape.
*/
public final class RelativeCornerSize implements CornerSize {

private final float percent;

public RelativeCornerSize(float percent) {
this.percent = percent;
}

/** Returns the relative percent used for this {@link CornerSize} */
public float getRelativePercent() {
return percent;
}

@Override
public float getCornerSize(@NonNull RectF bounds) {
return percent * bounds.height();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RelativeCornerSize)) {
return false;
}
RelativeCornerSize that = (RelativeCornerSize) o;
return percent == that.percent;
}

@Override
public int hashCode() {
Object[] hashedFields = {percent};
return Arrays.hashCode(hashedFields);
}
}
Loading

0 comments on commit c831ecc

Please sign in to comment.