1 /* 2 * Copyright 2018 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 package androidx.cardview.widget; 17 18 import android.content.Context; 19 import android.content.res.ColorStateList; 20 import android.graphics.Canvas; 21 import android.graphics.Paint; 22 import android.graphics.Rect; 23 import android.graphics.RectF; 24 25 import androidx.annotation.Nullable; 26 27 class CardViewBaseImpl implements CardViewImpl { 28 29 private final RectF mCornerRect = new RectF(); 30 31 @Override initStatic()32 public void initStatic() { 33 // Draws a round rect using 7 draw operations. This is faster than using 34 // canvas.drawRoundRect before JBMR1 because API 11-16 used alpha mask textures to draw 35 // shapes. 36 RoundRectDrawableWithShadow.sRoundRectHelper = 37 new RoundRectDrawableWithShadow.RoundRectHelper() { 38 @Override 39 public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, 40 Paint paint) { 41 final float twoRadius = cornerRadius * 2; 42 final float innerWidth = bounds.width() - twoRadius - 1; 43 final float innerHeight = bounds.height() - twoRadius - 1; 44 if (cornerRadius >= 1f) { 45 // increment corner radius to account for half pixels. 46 float roundedCornerRadius = cornerRadius + .5f; 47 mCornerRect.set(-roundedCornerRadius, -roundedCornerRadius, roundedCornerRadius, 48 roundedCornerRadius); 49 int saved = canvas.save(); 50 canvas.translate(bounds.left + roundedCornerRadius, 51 bounds.top + roundedCornerRadius); 52 canvas.drawArc(mCornerRect, 180, 90, true, paint); 53 canvas.translate(innerWidth, 0); 54 canvas.rotate(90); 55 canvas.drawArc(mCornerRect, 180, 90, true, paint); 56 canvas.translate(innerHeight, 0); 57 canvas.rotate(90); 58 canvas.drawArc(mCornerRect, 180, 90, true, paint); 59 canvas.translate(innerWidth, 0); 60 canvas.rotate(90); 61 canvas.drawArc(mCornerRect, 180, 90, true, paint); 62 canvas.restoreToCount(saved); 63 //draw top and bottom pieces 64 canvas.drawRect(bounds.left + roundedCornerRadius - 1f, bounds.top, 65 bounds.right - roundedCornerRadius + 1f, 66 bounds.top + roundedCornerRadius, paint); 67 68 canvas.drawRect(bounds.left + roundedCornerRadius - 1f, 69 bounds.bottom - roundedCornerRadius, 70 bounds.right - roundedCornerRadius + 1f, bounds.bottom, paint); 71 } 72 // center 73 canvas.drawRect(bounds.left, bounds.top + cornerRadius, 74 bounds.right, bounds.bottom - cornerRadius , paint); 75 } 76 }; 77 } 78 79 @Override initialize(CardViewDelegate cardView, Context context, ColorStateList backgroundColor, float radius, float elevation, float maxElevation)80 public void initialize(CardViewDelegate cardView, Context context, 81 ColorStateList backgroundColor, float radius, float elevation, float maxElevation) { 82 RoundRectDrawableWithShadow background = createBackground(context, backgroundColor, radius, 83 elevation, maxElevation); 84 background.setAddPaddingForCorners(cardView.getPreventCornerOverlap()); 85 cardView.setCardBackground(background); 86 updatePadding(cardView); 87 } 88 createBackground(Context context, ColorStateList backgroundColor, float radius, float elevation, float maxElevation)89 private RoundRectDrawableWithShadow createBackground(Context context, 90 ColorStateList backgroundColor, float radius, float elevation, 91 float maxElevation) { 92 return new RoundRectDrawableWithShadow(context.getResources(), backgroundColor, radius, 93 elevation, maxElevation); 94 } 95 96 @Override updatePadding(CardViewDelegate cardView)97 public void updatePadding(CardViewDelegate cardView) { 98 Rect shadowPadding = new Rect(); 99 getShadowBackground(cardView).getMaxShadowAndCornerPadding(shadowPadding); 100 cardView.setMinWidthHeightInternal((int) Math.ceil(getMinWidth(cardView)), 101 (int) Math.ceil(getMinHeight(cardView))); 102 cardView.setShadowPadding(shadowPadding.left, shadowPadding.top, 103 shadowPadding.right, shadowPadding.bottom); 104 } 105 106 @Override onCompatPaddingChanged(CardViewDelegate cardView)107 public void onCompatPaddingChanged(CardViewDelegate cardView) { 108 // NO OP 109 } 110 111 @Override onPreventCornerOverlapChanged(CardViewDelegate cardView)112 public void onPreventCornerOverlapChanged(CardViewDelegate cardView) { 113 getShadowBackground(cardView).setAddPaddingForCorners(cardView.getPreventCornerOverlap()); 114 updatePadding(cardView); 115 } 116 117 @Override setBackgroundColor(CardViewDelegate cardView, @Nullable ColorStateList color)118 public void setBackgroundColor(CardViewDelegate cardView, @Nullable ColorStateList color) { 119 getShadowBackground(cardView).setColor(color); 120 } 121 122 @Override getBackgroundColor(CardViewDelegate cardView)123 public ColorStateList getBackgroundColor(CardViewDelegate cardView) { 124 return getShadowBackground(cardView).getColor(); 125 } 126 127 @Override setRadius(CardViewDelegate cardView, float radius)128 public void setRadius(CardViewDelegate cardView, float radius) { 129 getShadowBackground(cardView).setCornerRadius(radius); 130 updatePadding(cardView); 131 } 132 133 @Override getRadius(CardViewDelegate cardView)134 public float getRadius(CardViewDelegate cardView) { 135 return getShadowBackground(cardView).getCornerRadius(); 136 } 137 138 @Override setElevation(CardViewDelegate cardView, float elevation)139 public void setElevation(CardViewDelegate cardView, float elevation) { 140 getShadowBackground(cardView).setShadowSize(elevation); 141 } 142 143 @Override getElevation(CardViewDelegate cardView)144 public float getElevation(CardViewDelegate cardView) { 145 return getShadowBackground(cardView).getShadowSize(); 146 } 147 148 @Override setMaxElevation(CardViewDelegate cardView, float maxElevation)149 public void setMaxElevation(CardViewDelegate cardView, float maxElevation) { 150 getShadowBackground(cardView).setMaxShadowSize(maxElevation); 151 updatePadding(cardView); 152 } 153 154 @Override getMaxElevation(CardViewDelegate cardView)155 public float getMaxElevation(CardViewDelegate cardView) { 156 return getShadowBackground(cardView).getMaxShadowSize(); 157 } 158 159 @Override getMinWidth(CardViewDelegate cardView)160 public float getMinWidth(CardViewDelegate cardView) { 161 return getShadowBackground(cardView).getMinWidth(); 162 } 163 164 @Override getMinHeight(CardViewDelegate cardView)165 public float getMinHeight(CardViewDelegate cardView) { 166 return getShadowBackground(cardView).getMinHeight(); 167 } 168 getShadowBackground(CardViewDelegate cardView)169 private RoundRectDrawableWithShadow getShadowBackground(CardViewDelegate cardView) { 170 return ((RoundRectDrawableWithShadow) cardView.getCardBackground()); 171 } 172 } 173