|
17 | 17 |
|
18 | 18 | import com.google.android.material.R; |
19 | 19 |
|
| 20 | +import static java.lang.Math.min; |
| 21 | + |
20 | 22 | import android.animation.Animator; |
21 | 23 | import android.animation.AnimatorListenerAdapter; |
22 | 24 | import android.animation.ObjectAnimator; |
|
28 | 30 | import android.graphics.Canvas; |
29 | 31 | import android.graphics.Color; |
30 | 32 | import android.graphics.Matrix; |
| 33 | +import android.graphics.Outline; |
31 | 34 | import android.graphics.Paint; |
32 | 35 | import android.graphics.Paint.Style; |
33 | 36 | import android.graphics.Path; |
|
36 | 39 | import android.graphics.drawable.ColorDrawable; |
37 | 40 | import android.graphics.drawable.Drawable; |
38 | 41 | import android.graphics.drawable.DrawableWrapper; |
| 42 | +import android.graphics.drawable.GradientDrawable; |
39 | 43 | import android.graphics.drawable.LayerDrawable; |
40 | 44 | import android.graphics.drawable.RippleDrawable; |
| 45 | +import android.graphics.drawable.ShapeDrawable; |
41 | 46 | import android.os.Build.VERSION; |
42 | 47 | import android.os.Build.VERSION_CODES; |
43 | 48 | import android.util.AttributeSet; |
@@ -822,25 +827,101 @@ private float calculateInnerRadius(float outerRadius) { |
822 | 827 |
|
823 | 828 | private void calculateShapeAppearanceRoundRectOrPath() { |
824 | 829 | if (state.ringShapeAppearance != null) { |
825 | | - calculateBounds(tmpRectF); |
| 830 | + updateShapeAppearanceCornerSizeOrPath(state.ringShapeAppearance); |
| 831 | + return; |
| 832 | + } |
| 833 | + ShapeAppearance shapeAppearance = toShapeAppearance(getDrawable()); |
| 834 | + if (shapeAppearance != null) { |
| 835 | + updateShapeAppearanceCornerSizeOrPath(shapeAppearance); |
| 836 | + return; |
| 837 | + } |
| 838 | + shapeAppearanceCornerSize = -1; |
| 839 | + shapeAppearancePath.reset(); |
| 840 | + } |
826 | 841 |
|
827 | | - ShapeAppearanceModel shapeAppearanceModel = |
828 | | - state.ringShapeAppearance.getShapeForState(FOCUSED_STATE_SET); |
| 842 | + private void updateShapeAppearanceCornerSizeOrPath(ShapeAppearance shapeAppearance) { |
| 843 | + calculateBounds(tmpRectF); |
829 | 844 |
|
830 | | - if (shapeAppearanceModel.isRoundRect(tmpRectF)) { |
831 | | - float outerInset = calculateOuterInset(); |
832 | | - tmpRectF.inset(outerInset, outerInset); |
833 | | - shapeAppearanceCornerSize = |
834 | | - shapeAppearanceModel.getTopLeftCornerSize().getCornerSize(tmpRectF); |
835 | | - shapeAppearancePath.reset(); |
836 | | - } else { |
837 | | - pathProvider.calculatePath( |
838 | | - shapeAppearanceModel, null, 1, tmpRectF, null, shapeAppearancePath); |
839 | | - shapeAppearanceCornerSize = -1; |
840 | | - } |
| 845 | + ShapeAppearanceModel shapeAppearanceModel = shapeAppearance.getShapeForState(FOCUSED_STATE_SET); |
| 846 | + |
| 847 | + if (shapeAppearanceModel.isRoundRect(tmpRectF)) { |
| 848 | + float outerInset = calculateOuterInset(); |
| 849 | + tmpRectF.inset(outerInset, outerInset); |
| 850 | + shapeAppearanceCornerSize = |
| 851 | + shapeAppearanceModel.getTopLeftCornerSize().getCornerSize(tmpRectF); |
| 852 | + shapeAppearancePath.reset(); |
841 | 853 | } else { |
| 854 | + pathProvider.calculatePath( |
| 855 | + shapeAppearanceModel, null, 1, tmpRectF, null, shapeAppearancePath); |
842 | 856 | shapeAppearanceCornerSize = -1; |
843 | | - shapeAppearancePath.reset(); |
| 857 | + } |
| 858 | + } |
| 859 | + |
| 860 | + @Nullable |
| 861 | + private ShapeAppearance toShapeAppearance(@Nullable Drawable drawable) { |
| 862 | + if (drawable instanceof ShapeDrawable) { |
| 863 | + return toShapeAppearance((ShapeDrawable) drawable); |
| 864 | + } |
| 865 | + if (drawable instanceof GradientDrawable) { |
| 866 | + return toShapeAppearance((GradientDrawable) drawable); |
| 867 | + } |
| 868 | + return null; |
| 869 | + } |
| 870 | + |
| 871 | + @Nullable |
| 872 | + private ShapeAppearance toShapeAppearance(@NonNull ShapeDrawable shapeDrawable) { |
| 873 | + if (VERSION.SDK_INT < VERSION_CODES.N) { |
| 874 | + return null; |
| 875 | + } |
| 876 | + Outline outline = new Outline(); |
| 877 | + shapeDrawable.getOutline(outline); |
| 878 | + if (outline.getRadius() > 0) { |
| 879 | + return ShapeAppearanceModel.builder().setAllCornerSizes(outline.getRadius()).build(); |
| 880 | + } |
| 881 | + return null; |
| 882 | + } |
| 883 | + |
| 884 | + @Nullable |
| 885 | + private ShapeAppearance toShapeAppearance(@NonNull GradientDrawable gradientDrawable) { |
| 886 | + if (VERSION.SDK_INT < VERSION_CODES.N) { |
| 887 | + return null; |
| 888 | + } |
| 889 | + float[] cornerRadii = getCornerRadiiOrNull(gradientDrawable); |
| 890 | + if (cornerRadii != null) { |
| 891 | + // ShapeAppearance doesn't support different x and y radius values for each corner, so just |
| 892 | + // take the min of x and y for now, which shouldn't be different in most cases. |
| 893 | + return ShapeAppearanceModel.builder() |
| 894 | + .setTopLeftCornerSize(min(cornerRadii[0], cornerRadii[1])) |
| 895 | + .setTopRightCornerSize(min(cornerRadii[2], cornerRadii[3])) |
| 896 | + .setBottomRightCornerSize(min(cornerRadii[4], cornerRadii[5])) |
| 897 | + .setBottomLeftCornerSize(min(cornerRadii[6], cornerRadii[7])) |
| 898 | + .build(); |
| 899 | + } |
| 900 | + float cornerRadius = getCornerRadius(gradientDrawable); |
| 901 | + if (cornerRadius > 0) { |
| 902 | + return ShapeAppearanceModel.builder().setAllCornerSizes(cornerRadius).build(); |
| 903 | + } |
| 904 | + return null; |
| 905 | + } |
| 906 | + |
| 907 | + @RequiresApi(api = VERSION_CODES.N) |
| 908 | + @Nullable |
| 909 | + private float[] getCornerRadiiOrNull(GradientDrawable gradientDrawable) { |
| 910 | + // Calling getCornerRadii() before GradientDrawable has its state causes an NPE. |
| 911 | + try { |
| 912 | + return gradientDrawable.getCornerRadii(); |
| 913 | + } catch (NullPointerException e) { |
| 914 | + return null; |
| 915 | + } |
| 916 | + } |
| 917 | + |
| 918 | + @RequiresApi(api = VERSION_CODES.N) |
| 919 | + private float getCornerRadius(GradientDrawable gradientDrawable) { |
| 920 | + // Calling getCornerRadius() before GradientDrawable has its state causes an NPE. |
| 921 | + try { |
| 922 | + return gradientDrawable.getCornerRadius(); |
| 923 | + } catch (NullPointerException e) { |
| 924 | + return -1f; |
844 | 925 | } |
845 | 926 | } |
846 | 927 |
|
|
0 commit comments