├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── colors_all.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── drawable-v21
│ │ │ │ ├── item_selector.xml
│ │ │ │ └── state_list_animator.xml
│ │ │ ├── drawable
│ │ │ │ ├── bg_round_rect_normal.xml
│ │ │ │ ├── bg_round_rect_pressed.xml
│ │ │ │ ├── bg_round_rect_white.xml
│ │ │ │ ├── bg_round_rect_selector.xml
│ │ │ │ ├── item_selector.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── zyp
│ │ │ │ └── cardview
│ │ │ │ └── demo
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── zyp
│ │ │ └── cardview
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── zyp
│ │ └── cardview
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── cardview
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── values-v23
│ │ │ └── values-v23.xml
│ │ └── values
│ │ │ └── values.xml
│ │ └── java
│ │ └── com
│ │ └── zyp
│ │ └── cardview
│ │ ├── YcCardViewDelegate.java
│ │ ├── YcCardViewJellybeanMr1.java
│ │ ├── YcCardViewImpl.java
│ │ ├── YcCardViewApi21.java
│ │ ├── YcRoundRectDrawable.java
│ │ ├── YcCardViewEclairMr1.java
│ │ ├── YcRoundRectDrawableWithShadow.java
│ │ └── YcCardView.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── shadow.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
└── misc.xml
├── gradle.properties
├── .gitignore
├── gradlew.bat
├── README.md
├── gradlew
└── LICENSE
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/cardview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':cardview'
2 |
--------------------------------------------------------------------------------
/shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzyyppqq/CardViewShadowColor/HEAD/shadow.png
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
24 | * Necessary to resolve circular dependency between base CardView and platform implementations.
25 | */
26 | interface YcCardViewDelegate {
27 | void setCardBackground(Drawable drawable);
28 | Drawable getCardBackground();
29 | boolean getUseCompatPadding();
30 | boolean getPreventCornerOverlap();
31 | void setShadowPadding(int left, int top, int right, int bottom);
32 | void setMinWidthHeightInternal(int width, int height);
33 | View getCardView();
34 | }
--------------------------------------------------------------------------------
/cardview/src/main/java/com/zyp/cardview/YcCardViewJellybeanMr1.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 com.zyp.cardview;
17 |
18 | import android.graphics.Canvas;
19 | import android.graphics.Paint;
20 | import android.graphics.RectF;
21 |
22 | class YcCardViewJellybeanMr1 extends YcCardViewEclairMr1 {
23 |
24 | @Override
25 | public void initStatic() {
26 | YcRoundRectDrawableWithShadow.sRoundRectHelper
27 | = new YcRoundRectDrawableWithShadow.RoundRectHelper() {
28 | @Override
29 | public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius,
30 | Paint paint) {
31 | canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
32 | }
33 | };
34 | }
35 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
19 |
24 |
37 | * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable.
38 | */
39 | class YcRoundRectDrawable extends Drawable {
40 | private float mRadius;
41 | private final Paint mPaint;
42 | private final RectF mBoundsF;
43 | private final Rect mBoundsI;
44 | private float mPadding;
45 | private boolean mInsetForPadding = false;
46 | private boolean mInsetForRadius = true;
47 |
48 | private PorterDuffColorFilter mTintFilter;
49 | private ColorStateList mTint;
50 | private PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_IN;
51 |
52 | public YcRoundRectDrawable(int backgroundColor, float radius) {
53 | Log.e("AAA","RoundRectDrawable");
54 | mRadius = radius;
55 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
56 | mPaint.setColor(backgroundColor);
57 | mBoundsF = new RectF();
58 | mBoundsI = new Rect();
59 | }
60 |
61 | void setPadding(float padding, boolean insetForPadding, boolean insetForRadius) {
62 | if (padding == mPadding && mInsetForPadding == insetForPadding &&
63 | mInsetForRadius == insetForRadius) {
64 | return;
65 | }
66 | mPadding = padding;
67 | mInsetForPadding = insetForPadding;
68 | mInsetForRadius = insetForRadius;
69 | updateBounds(null);
70 | invalidateSelf();
71 | }
72 |
73 | float getPadding() {
74 | return mPadding;
75 | }
76 |
77 | @Override
78 | public void draw(Canvas canvas) {
79 | final Paint paint = mPaint;
80 |
81 | final boolean clearColorFilter;
82 | if (mTintFilter != null && paint.getColorFilter() == null) {
83 | paint.setColorFilter(mTintFilter);
84 | clearColorFilter = true;
85 | } else {
86 | clearColorFilter = false;
87 | }
88 |
89 | canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint);
90 |
91 | if (clearColorFilter) {
92 | paint.setColorFilter(null);
93 | }
94 | }
95 |
96 | private void updateBounds(Rect bounds) {
97 | if (bounds == null) {
98 | bounds = getBounds();
99 | }
100 | mBoundsF.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
101 | mBoundsI.set(bounds);
102 | if (mInsetForPadding) {
103 | float vInset = YcRoundRectDrawableWithShadow.calculateVerticalPadding(mPadding, mRadius, mInsetForRadius);
104 | float hInset = YcRoundRectDrawableWithShadow.calculateHorizontalPadding(mPadding, mRadius, mInsetForRadius);
105 | mBoundsI.inset((int) Math.ceil(hInset), (int) Math.ceil(vInset));
106 | // to make sure they have same bounds.
107 | mBoundsF.set(mBoundsI);
108 | }
109 | }
110 |
111 | @Override
112 | protected void onBoundsChange(Rect bounds) {
113 | super.onBoundsChange(bounds);
114 | updateBounds(bounds);
115 | }
116 |
117 | @Override
118 | public void getOutline(Outline outline) {
119 | outline.setRoundRect(mBoundsI, mRadius);
120 | }
121 |
122 | void setRadius(float radius) {
123 | if (radius == mRadius) {
124 | return;
125 | }
126 | mRadius = radius;
127 | updateBounds(null);
128 | invalidateSelf();
129 | }
130 |
131 | @Override
132 | public void setAlpha(int alpha) {
133 | mPaint.setAlpha(alpha);
134 | }
135 |
136 | @Override
137 | public void setColorFilter(ColorFilter cf) {
138 | mPaint.setColorFilter(cf);
139 | }
140 |
141 | @Override
142 | public int getOpacity() {
143 | return PixelFormat.TRANSLUCENT;
144 | }
145 |
146 | public float getRadius() {
147 | return mRadius;
148 | }
149 |
150 | public void setColor(int color) {
151 | mPaint.setColor(color);
152 | invalidateSelf();
153 | }
154 |
155 | @Override
156 | public void setTintList(ColorStateList tint) {
157 | mTint = tint;
158 | mTintFilter = createTintFilter(mTint, mTintMode);
159 | invalidateSelf();
160 | }
161 |
162 | @Override
163 | public void setTintMode(PorterDuff.Mode tintMode) {
164 | mTintMode = tintMode;
165 | mTintFilter = createTintFilter(mTint, mTintMode);
166 | invalidateSelf();
167 | }
168 |
169 | @Override
170 | protected boolean onStateChange(int[] stateSet) {
171 | if (mTint != null && mTintMode != null) {
172 | mTintFilter = createTintFilter(mTint, mTintMode);
173 | return true;
174 | }
175 | return false;
176 | }
177 |
178 | @Override
179 | public boolean isStateful() {
180 | return (mTint != null && mTint.isStateful()) || super.isStateful();
181 | }
182 |
183 | /**
184 | * Ensures the tint filter is consistent with the current tint color and
185 | * mode.
186 | */
187 | private PorterDuffColorFilter createTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) {
188 | if (tint == null || tintMode == null) {
189 | return null;
190 | }
191 | final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
192 | return new PorterDuffColorFilter(color, tintMode);
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/cardview/src/main/java/com/zyp/cardview/YcCardViewEclairMr1.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 com.zyp.cardview;
17 |
18 | import android.content.Context;
19 | import android.graphics.Canvas;
20 | import android.graphics.Paint;
21 | import android.graphics.Rect;
22 | import android.graphics.RectF;
23 |
24 | class YcCardViewEclairMr1 implements YcCardViewImpl {
25 |
26 | final RectF sCornerRect = new RectF();
27 |
28 | @Override
29 | public void initStatic() {
30 | // Draws a round rect using 7 draw operations. This is faster than using
31 | // canvas.drawRoundRect before JBMR1 because API 11-16 used alpha mask textures to draw
32 | // shapes.
33 | YcRoundRectDrawableWithShadow.sRoundRectHelper =
34 | new YcRoundRectDrawableWithShadow.RoundRectHelper() {
35 | @Override
36 | public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius,
37 | Paint paint) {
38 | final float twoRadius = cornerRadius * 2;
39 | final float innerWidth = bounds.width() - twoRadius - 1;
40 | final float innerHeight = bounds.height() - twoRadius - 1;
41 | if (cornerRadius >= 1f) {
42 | // increment corner radius to account for half pixels.
43 | float roundedCornerRadius = cornerRadius + .5f;
44 | sCornerRect.set(-roundedCornerRadius, -roundedCornerRadius, roundedCornerRadius,
45 | roundedCornerRadius);
46 | int saved = canvas.save();
47 | canvas.translate(bounds.left + roundedCornerRadius,
48 | bounds.top + roundedCornerRadius);
49 | canvas.drawArc(sCornerRect, 180, 90, true, paint);
50 | canvas.translate(innerWidth, 0);
51 | canvas.rotate(90);
52 | canvas.drawArc(sCornerRect, 180, 90, true, paint);
53 | canvas.translate(innerHeight, 0);
54 | canvas.rotate(90);
55 | canvas.drawArc(sCornerRect, 180, 90, true, paint);
56 | canvas.translate(innerWidth, 0);
57 | canvas.rotate(90);
58 | canvas.drawArc(sCornerRect, 180, 90, true, paint);
59 | canvas.restoreToCount(saved);
60 | //draw top and bottom pieces
61 | canvas.drawRect(bounds.left + roundedCornerRadius - 1f, bounds.top,
62 | bounds.right - roundedCornerRadius + 1f,
63 | bounds.top + roundedCornerRadius, paint);
64 | canvas.drawRect(bounds.left + roundedCornerRadius - 1f,
65 | bounds.bottom - roundedCornerRadius + 1f,
66 | bounds.right - roundedCornerRadius + 1f, bounds.bottom, paint);
67 | }
68 | // center
69 | canvas.drawRect(bounds.left, bounds.top + Math.max(0, cornerRadius - 1f),
70 | bounds.right, bounds.bottom - cornerRadius + 1f, paint);
71 | }
72 | };
73 | }
74 |
75 | @Override
76 | public void initialize(YcCardViewDelegate cardView, Context context, int backgroundColor,
77 | float radius, float elevation, float maxElevation, int startShadowColor, int endShadowColor) {
78 | YcRoundRectDrawableWithShadow background = createBackground(context, backgroundColor, radius,
79 | elevation, maxElevation,startShadowColor,endShadowColor);
80 | background.setAddPaddingForCorners(cardView.getPreventCornerOverlap());
81 | cardView.setCardBackground(background);
82 | updatePadding(cardView);
83 | }
84 |
85 | private YcRoundRectDrawableWithShadow createBackground(Context context, int backgroundColor,
86 | float radius, float elevation, float maxElevation, int startShadowColor, int endShadowColor) {
87 | return new YcRoundRectDrawableWithShadow(context.getResources(), backgroundColor, radius,
88 | elevation, maxElevation,startShadowColor,endShadowColor);
89 | }
90 |
91 | @Override
92 | public void updatePadding(YcCardViewDelegate cardView) {
93 | Rect shadowPadding = new Rect();
94 | getShadowBackground(cardView).getMaxShadowAndCornerPadding(shadowPadding);
95 | cardView.setMinWidthHeightInternal((int) Math.ceil(getMinWidth(cardView)),
96 | (int) Math.ceil(getMinHeight(cardView)));
97 | cardView.setShadowPadding(shadowPadding.left, shadowPadding.top,
98 | shadowPadding.right, shadowPadding.bottom);
99 | }
100 |
101 | @Override
102 | public void onCompatPaddingChanged(YcCardViewDelegate cardView) {
103 | // NO OP
104 | }
105 |
106 | @Override
107 | public void onPreventCornerOverlapChanged(YcCardViewDelegate cardView) {
108 | getShadowBackground(cardView).setAddPaddingForCorners(cardView.getPreventCornerOverlap());
109 | updatePadding(cardView);
110 | }
111 |
112 | @Override
113 | public void setBackgroundColor(YcCardViewDelegate cardView, int color) {
114 | getShadowBackground(cardView).setColor(color);
115 | }
116 |
117 | @Override
118 | public void setRadius(YcCardViewDelegate cardView, float radius) {
119 | getShadowBackground(cardView).setCornerRadius(radius);
120 | updatePadding(cardView);
121 | }
122 |
123 | @Override
124 | public float getRadius(YcCardViewDelegate cardView) {
125 | return getShadowBackground(cardView).getCornerRadius();
126 | }
127 |
128 | @Override
129 | public void setElevation(YcCardViewDelegate cardView, float elevation) {
130 | getShadowBackground(cardView).setShadowSize(elevation);
131 | }
132 |
133 | @Override
134 | public float getElevation(YcCardViewDelegate cardView) {
135 | return getShadowBackground(cardView).getShadowSize();
136 | }
137 |
138 | @Override
139 | public void setMaxElevation(YcCardViewDelegate cardView, float maxElevation) {
140 | getShadowBackground(cardView).setMaxShadowSize(maxElevation);
141 | updatePadding(cardView);
142 | }
143 |
144 | @Override
145 | public float getMaxElevation(YcCardViewDelegate cardView) {
146 | return getShadowBackground(cardView).getMaxShadowSize();
147 | }
148 |
149 | @Override
150 | public float getMinWidth(YcCardViewDelegate cardView) {
151 | return getShadowBackground(cardView).getMinWidth();
152 | }
153 |
154 | @Override
155 | public float getMinHeight(YcCardViewDelegate cardView) {
156 | return getShadowBackground(cardView).getMinHeight();
157 | }
158 |
159 | private YcRoundRectDrawableWithShadow getShadowBackground(YcCardViewDelegate cardView) {
160 | return ((YcRoundRectDrawableWithShadow) cardView.getCardBackground());
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors_all.xml:
--------------------------------------------------------------------------------
1 |
2 |
46 | * Prior to API 17, canvas.drawRoundRect is expensive; which is why we need this interface 47 | * to draw efficient rounded rectangles before 17. 48 | * */ 49 | static RoundRectHelper sRoundRectHelper; 50 | 51 | Paint mPaint; 52 | 53 | Paint mCornerShadowPaint; 54 | 55 | Paint mEdgeShadowPaint; 56 | 57 | final RectF mCardBounds; 58 | 59 | float mCornerRadius; 60 | 61 | Path mCornerShadowPath; 62 | 63 | // updated value with inset 64 | float mMaxShadowSize; 65 | 66 | // actual value set by developer 67 | float mRawMaxShadowSize; 68 | 69 | // multiplied value to account for shadow offset 70 | float mShadowSize; 71 | 72 | // actual value set by developer 73 | float mRawShadowSize; 74 | 75 | private boolean mDirty = true; 76 | 77 | private int mShadowStartColor; 78 | 79 | private int mShadowEndColor; 80 | 81 | private boolean mAddPaddingForCorners = true; 82 | 83 | /** 84 | * If shadow size is set to a value above max shadow, we print a warning 85 | */ 86 | private boolean mPrintedShadowClipWarning = false; 87 | 88 | YcRoundRectDrawableWithShadow(Resources resources, int backgroundColor, float radius, 89 | float shadowSize, float maxShadowSize, int startShadowColor, int endShadowColor) { 90 | Log.e("AAA","RoundRectDrawableWithShadow"); 91 | if (startShadowColor != 0) { 92 | mShadowStartColor = startShadowColor; 93 | }else { 94 | mShadowStartColor = resources.getColor(R.color.yc_cardview_shadow_start_color); 95 | } 96 | if (endShadowColor != 0) { 97 | mShadowEndColor = endShadowColor; 98 | }else { 99 | mShadowEndColor = resources.getColor(R.color.yc_cardview_shadow_end_color); 100 | } 101 | mInsetShadow = resources.getDimensionPixelSize(R.dimen.yc_cardview_compat_inset_shadow); 102 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); 103 | mPaint.setColor(backgroundColor); 104 | mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); 105 | mCornerShadowPaint.setStyle(Paint.Style.FILL); 106 | mCornerRadius = (int) (radius + .5f); 107 | mCardBounds = new RectF(); 108 | mEdgeShadowPaint = new Paint(mCornerShadowPaint); 109 | mEdgeShadowPaint.setAntiAlias(false); 110 | setShadowSize(shadowSize, maxShadowSize); 111 | } 112 | 113 | /** 114 | * Casts the value to an even integer. 115 | */ 116 | private int toEven(float value) { 117 | int i = (int) (value + .5f); 118 | if (i % 2 == 1) { 119 | return i - 1; 120 | } 121 | return i; 122 | } 123 | 124 | public void setAddPaddingForCorners(boolean addPaddingForCorners) { 125 | mAddPaddingForCorners = addPaddingForCorners; 126 | invalidateSelf(); 127 | } 128 | 129 | @Override 130 | public void setAlpha(int alpha) { 131 | mPaint.setAlpha(alpha); 132 | mCornerShadowPaint.setAlpha(alpha); 133 | mEdgeShadowPaint.setAlpha(alpha); 134 | } 135 | 136 | @Override 137 | protected void onBoundsChange(Rect bounds) { 138 | super.onBoundsChange(bounds); 139 | mDirty = true; 140 | } 141 | 142 | void setShadowSize(float shadowSize, float maxShadowSize) { 143 | if (shadowSize < 0f) { 144 | throw new IllegalArgumentException("Invalid shadow size " + shadowSize + 145 | ". Must be >= 0"); 146 | } 147 | if (maxShadowSize < 0f) { 148 | throw new IllegalArgumentException("Invalid max shadow size " + maxShadowSize + 149 | ". Must be >= 0"); 150 | } 151 | shadowSize = toEven(shadowSize); 152 | maxShadowSize = toEven(maxShadowSize); 153 | if (shadowSize > maxShadowSize) { 154 | shadowSize = maxShadowSize; 155 | if (!mPrintedShadowClipWarning) { 156 | mPrintedShadowClipWarning = true; 157 | } 158 | } 159 | if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) { 160 | return; 161 | } 162 | mRawShadowSize = shadowSize; 163 | mRawMaxShadowSize = maxShadowSize; 164 | mShadowSize = (int)(shadowSize * SHADOW_MULTIPLIER + mInsetShadow + .5f); 165 | mMaxShadowSize = maxShadowSize + mInsetShadow; 166 | mDirty = true; 167 | invalidateSelf(); 168 | } 169 | 170 | @Override 171 | public boolean getPadding(Rect padding) { 172 | int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius, 173 | mAddPaddingForCorners)); 174 | int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius, 175 | mAddPaddingForCorners)); 176 | padding.set(hOffset, vOffset, hOffset, vOffset); 177 | return true; 178 | } 179 | 180 | static float calculateVerticalPadding(float maxShadowSize, float cornerRadius, 181 | boolean addPaddingForCorners) { 182 | if (addPaddingForCorners) { 183 | return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius); 184 | } else { 185 | return maxShadowSize * SHADOW_MULTIPLIER; 186 | } 187 | } 188 | 189 | static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius, 190 | boolean addPaddingForCorners) { 191 | if (addPaddingForCorners) { 192 | return (float) (maxShadowSize + (1 - COS_45) * cornerRadius); 193 | } else { 194 | return maxShadowSize; 195 | } 196 | } 197 | 198 | @Override 199 | public void setColorFilter(ColorFilter cf) { 200 | mPaint.setColorFilter(cf); 201 | } 202 | 203 | @Override 204 | public int getOpacity() { 205 | return PixelFormat.TRANSLUCENT; 206 | } 207 | 208 | void setCornerRadius(float radius) { 209 | if (radius < 0f) { 210 | throw new IllegalArgumentException("Invalid radius " + radius + 211 | ". Must be >= 0"); 212 | } 213 | radius = (int) (radius + .5f); 214 | if (mCornerRadius == radius) { 215 | return; 216 | } 217 | mCornerRadius = radius; 218 | mDirty = true; 219 | invalidateSelf(); 220 | } 221 | 222 | @Override 223 | public void draw(Canvas canvas) { 224 | if (mDirty) { 225 | buildComponents(getBounds()); 226 | mDirty = false; 227 | } 228 | canvas.translate(0, mRawShadowSize / 2); 229 | drawShadow(canvas); 230 | canvas.translate(0, -mRawShadowSize / 2); 231 | sRoundRectHelper.drawRoundRect(canvas, mCardBounds, mCornerRadius, mPaint); 232 | } 233 | 234 | private void drawShadow(Canvas canvas) { 235 | final float edgeShadowTop = -mCornerRadius - mShadowSize; 236 | final float inset = mCornerRadius + mInsetShadow + mRawShadowSize / 2; 237 | final boolean drawHorizontalEdges = mCardBounds.width() - 2 * inset > 0; 238 | final boolean drawVerticalEdges = mCardBounds.height() - 2 * inset > 0; 239 | // LT 240 | int saved = canvas.save(); 241 | canvas.translate(mCardBounds.left + inset, mCardBounds.top + inset); 242 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 243 | if (drawHorizontalEdges) { 244 | canvas.drawRect(0, edgeShadowTop, 245 | mCardBounds.width() - 2 * inset, -mCornerRadius, 246 | mEdgeShadowPaint); 247 | } 248 | canvas.restoreToCount(saved); 249 | // RB 250 | saved = canvas.save(); 251 | canvas.translate(mCardBounds.right - inset, mCardBounds.bottom - inset); 252 | canvas.rotate(180f); 253 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 254 | if (drawHorizontalEdges) { 255 | canvas.drawRect(0, edgeShadowTop, 256 | mCardBounds.width() - 2 * inset, -mCornerRadius + mShadowSize, 257 | mEdgeShadowPaint); 258 | } 259 | canvas.restoreToCount(saved); 260 | // LB 261 | saved = canvas.save(); 262 | canvas.translate(mCardBounds.left + inset, mCardBounds.bottom - inset); 263 | canvas.rotate(270f); 264 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 265 | if (drawVerticalEdges) { 266 | canvas.drawRect(0, edgeShadowTop, 267 | mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); 268 | } 269 | canvas.restoreToCount(saved); 270 | // RT 271 | saved = canvas.save(); 272 | canvas.translate(mCardBounds.right - inset, mCardBounds.top + inset); 273 | canvas.rotate(90f); 274 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 275 | if (drawVerticalEdges) { 276 | canvas.drawRect(0, edgeShadowTop, 277 | mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); 278 | } 279 | canvas.restoreToCount(saved); 280 | } 281 | 282 | private void buildShadowCorners() { 283 | RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius); 284 | RectF outerBounds = new RectF(innerBounds); 285 | outerBounds.inset(-mShadowSize, -mShadowSize); 286 | 287 | if (mCornerShadowPath == null) { 288 | mCornerShadowPath = new Path(); 289 | } else { 290 | mCornerShadowPath.reset(); 291 | } 292 | mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD); 293 | mCornerShadowPath.moveTo(-mCornerRadius, 0); 294 | mCornerShadowPath.rLineTo(-mShadowSize, 0); 295 | // outer arc 296 | mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false); 297 | // inner arc 298 | mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false); 299 | mCornerShadowPath.close(); 300 | float startRatio = mCornerRadius / (mCornerRadius + mShadowSize); 301 | mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize, 302 | new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, 303 | new float[]{0f, startRatio, 1f} 304 | , Shader.TileMode.CLAMP)); 305 | 306 | // we offset the content shadowSize/2 pixels up to make it more realistic. 307 | // this is why edge shadow shader has some extra space 308 | // When drawing bottom edge shadow, we use that extra space. 309 | mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0, 310 | -mCornerRadius - mShadowSize, 311 | new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, 312 | new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP)); 313 | mEdgeShadowPaint.setAntiAlias(false); 314 | } 315 | 316 | private void buildComponents(Rect bounds) { 317 | // Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift. 318 | // We could have different top-bottom offsets to avoid extra gap above but in that case 319 | // center aligning Views inside the CardView would be problematic. 320 | final float verticalOffset = mRawMaxShadowSize * SHADOW_MULTIPLIER; 321 | mCardBounds.set(bounds.left + mRawMaxShadowSize, bounds.top + verticalOffset, 322 | bounds.right - mRawMaxShadowSize, bounds.bottom - verticalOffset); 323 | buildShadowCorners(); 324 | } 325 | 326 | float getCornerRadius() { 327 | return mCornerRadius; 328 | } 329 | 330 | void getMaxShadowAndCornerPadding(Rect into) { 331 | getPadding(into); 332 | } 333 | 334 | void setShadowSize(float size) { 335 | setShadowSize(size, mRawMaxShadowSize); 336 | } 337 | 338 | void setMaxShadowSize(float size) { 339 | setShadowSize(mRawShadowSize, size); 340 | } 341 | 342 | float getShadowSize() { 343 | return mRawShadowSize; 344 | } 345 | 346 | float getMaxShadowSize() { 347 | return mRawMaxShadowSize; 348 | } 349 | 350 | float getMinWidth() { 351 | final float content = 2 * 352 | Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize / 2); 353 | return content + (mRawMaxShadowSize + mInsetShadow) * 2; 354 | } 355 | 356 | float getMinHeight() { 357 | final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow 358 | + mRawMaxShadowSize * SHADOW_MULTIPLIER / 2); 359 | return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER + mInsetShadow) * 2; 360 | } 361 | 362 | public void setColor(int color) { 363 | mPaint.setColor(color); 364 | invalidateSelf(); 365 | } 366 | 367 | static interface RoundRectHelper { 368 | void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint); 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /cardview/src/main/java/com/zyp/cardview/YcCardView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 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.zyp.cardview; 18 | 19 | import android.content.Context; 20 | import android.content.res.TypedArray; 21 | import android.graphics.Color; 22 | import android.graphics.Rect; 23 | import android.graphics.drawable.Drawable; 24 | import android.os.Build; 25 | import android.util.AttributeSet; 26 | import android.view.View; 27 | import android.widget.FrameLayout; 28 | 29 | /** 30 | * A FrameLayout with a rounded corner background and shadow. 31 | *
32 | * CardView uses elevation property on Lollipop for shadows and falls back to a
33 | * custom emulated shadow implementation on older platforms.
34 | *
35 | * Due to expensive nature of rounded corner clipping, on platforms before Lollipop, CardView does 36 | * not clip its children that intersect with rounded corners. Instead, it adds padding to avoid such 37 | * intersection (See {@link #setPreventCornerOverlap(boolean)} to change this behavior). 38 | *
39 | * Before Lollipop, CardView adds padding to its content and draws shadows to that area. This
40 | * padding amount is equal to maxCardElevation + (1 - cos45) * cornerRadius on the
41 | * sides and maxCardElevation * 1.5 + (1 - cos45) * cornerRadius on top and bottom.
42 | *
43 | * Since padding is used to offset content for shadows, you cannot set padding on CardView. 44 | * Instead, you can use content padding attributes in XML or 45 | * {@link #setContentPadding(int, int, int, int)} in code to set the padding between the edges of 46 | * the CardView and children of CardView. 47 | *
48 | * Note that, if you specify exact dimensions for the CardView, because of the shadows, its content
49 | * area will be different between platforms before Lollipop and after Lollipop. By using api version
50 | * specific resource values, you can avoid these changes. Alternatively, If you want CardView to add
51 | * inner padding on platforms Lollipop and after as well, you can call
52 | * {@link #setUseCompatPadding(boolean)} and pass true.
53 | *
54 | * To change CardView's elevation in a backward compatible way, use 55 | * {@link #setCardElevation(float)}. CardView will use elevation API on Lollipop and before 56 | * Lollipop, it will change the shadow size. To avoid moving the View while shadow size is changing, 57 | * shadow size is clamped by {@link #getMaxCardElevation()}. If you want to change elevation 58 | * dynamically, you should call {@link #setMaxCardElevation(float)} when CardView is initialized. 59 | * 60 | * ref com.zyp.cardview.R.styleable#YcCardView_cardBackgroundColor 61 | * ref com.zyp.cardview.R.styleable#YcCardView_cardCornerRadius 62 | * ref com.zyp.cardview.R.styleable#YcCardView_cardElevation 63 | * ref com.zyp.cardview.R.styleable#YcCardView_cardMaxElevation 64 | * ref com.zyp.cardview.R.styleable#YcCardView_cardUseCompatPadding 65 | * ref com.zyp.cardview.R.styleable#YcCardView_cardPreventCornerOverlap 66 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPadding 67 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingLeft 68 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingTop 69 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingRight 70 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingBottom 71 | */ 72 | public class YcCardView extends FrameLayout { 73 | 74 | private static final int[] COLOR_BACKGROUND_ATTR = {android.R.attr.colorBackground}; 75 | private static final YcCardViewImpl IMPL; 76 | 77 | static { 78 | // if (Build.VERSION.SDK_INT >= 21) { 79 | // IMPL = new YcCardViewApi21(); 80 | // } else 81 | if (Build.VERSION.SDK_INT >= 17) { 82 | IMPL = new YcCardViewJellybeanMr1(); 83 | } else { 84 | IMPL = new YcCardViewEclairMr1(); 85 | } 86 | 87 | IMPL.initStatic(); 88 | } 89 | 90 | private boolean mCompatPadding; 91 | 92 | private boolean mPreventCornerOverlap; 93 | 94 | /** 95 | * CardView requires to have a particular minimum size to draw shadows before API 21. If 96 | * developer also sets min width/height, they might be overridden. 97 | *
98 | * CardView works around this issue by recording user given parameters and using an internal
99 | * method to set them.
100 | */
101 | private int mUserSetMinWidth, mUserSetMinHeight;
102 |
103 | private final Rect mContentPadding = new Rect();
104 |
105 | private final Rect mShadowBounds = new Rect();
106 | private int startShadowColor;
107 | private int endShadowColor;
108 |
109 | public YcCardView(Context context) {
110 | super(context);
111 | initialize(context, null, 0);
112 | }
113 |
114 | public YcCardView(Context context, AttributeSet attrs) {
115 | super(context, attrs);
116 | initialize(context, attrs, 0);
117 | }
118 |
119 | public YcCardView(Context context, AttributeSet attrs, int defStyleAttr) {
120 | super(context, attrs, defStyleAttr);
121 | initialize(context, attrs, defStyleAttr);
122 | }
123 |
124 | @Override
125 | public void setPadding(int left, int top, int right, int bottom) {
126 | // NO OP
127 | }
128 |
129 | public void setPaddingRelative(int start, int top, int end, int bottom) {
130 | // NO OP
131 | }
132 |
133 | /**
134 | * Returns whether CardView will add inner padding on platforms Lollipop and after.
135 | *
136 | * @return true if CardView adds inner padding on platforms Lollipop and after to
137 | * have same dimensions with platforms before Lollipop.
138 | */
139 | public boolean getUseCompatPadding() {
140 | return mCompatPadding;
141 | }
142 |
143 | /**
144 | * CardView adds additional padding to draw shadows on platforms before Lollipop.
145 | *
146 | * This may cause Cards to have different sizes between Lollipop and before Lollipop. If you
147 | * need to align CardView with other Views, you may need api version specific dimension
148 | * resources to account for the changes.
149 | * As an alternative, you can set this flag to true and CardView will add the same
150 | * padding values on platforms Lollipop and after.
151 | *
152 | * Since setting this flag to true adds unnecessary gaps in the UI, default value is
153 | * false.
154 | *
155 | * @param useCompatPadding true if CardView should add padding for the shadows on
156 | * platforms Lollipop and above.
157 | * ref com.zyp.cardview.R.styleable#YcCardView_ycCardUseCompatPadding
158 | */
159 | public void setUseCompatPadding(boolean useCompatPadding) {
160 | if (mCompatPadding != useCompatPadding) {
161 | mCompatPadding = useCompatPadding;
162 | IMPL.onCompatPaddingChanged(mCardViewDelegate);
163 | }
164 | }
165 |
166 | /**
167 | * Sets the padding between the Card's edges and the children of CardView.
168 | *
169 | * Depending on platform version or {@link #getUseCompatPadding()} settings, CardView may 170 | * update these values before calling {@link View#setPadding(int, int, int, int)}. 171 | * 172 | * @param left The left padding in pixels 173 | * @param top The top padding in pixels 174 | * @param right The right padding in pixels 175 | * @param bottom The bottom padding in pixels 176 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPadding 177 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingLeft 178 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingTop 179 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingRight 180 | * ref com.zyp.cardview.R.styleable#YcCardView_contentPaddingBottom 181 | */ 182 | public void setContentPadding(int left, int top, int right, int bottom) { 183 | mContentPadding.set(left, top, right, bottom); 184 | IMPL.updatePadding(mCardViewDelegate); 185 | } 186 | 187 | @Override 188 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 189 | if (!(IMPL instanceof YcCardViewApi21)) { 190 | final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 191 | switch (widthMode) { 192 | case MeasureSpec.EXACTLY: 193 | case MeasureSpec.AT_MOST: 194 | final int minWidth = (int) Math.ceil(IMPL.getMinWidth(mCardViewDelegate)); 195 | widthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minWidth, 196 | MeasureSpec.getSize(widthMeasureSpec)), widthMode); 197 | break; 198 | } 199 | 200 | final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 201 | switch (heightMode) { 202 | case MeasureSpec.EXACTLY: 203 | case MeasureSpec.AT_MOST: 204 | final int minHeight = (int) Math.ceil(IMPL.getMinHeight(mCardViewDelegate)); 205 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minHeight, 206 | MeasureSpec.getSize(heightMeasureSpec)), heightMode); 207 | break; 208 | } 209 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 210 | } else { 211 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 212 | } 213 | } 214 | 215 | private void initialize(Context context, AttributeSet attrs, int defStyleAttr) { 216 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.YcCardView, defStyleAttr, 217 | R.style.YcCardView); 218 | int backgroundColor; 219 | if (a.hasValue(R.styleable.YcCardView_ycCardBackgroundColor)) { 220 | backgroundColor = a.getColor(R.styleable.YcCardView_ycCardBackgroundColor, 0); 221 | } else { 222 | // There isn't one set, so we'll compute one based on the theme 223 | final TypedArray aa = getContext().obtainStyledAttributes(COLOR_BACKGROUND_ATTR); 224 | final int themeColorBackground = aa.getColor(0, 0); 225 | aa.recycle(); 226 | 227 | // If the theme colorBackground is light, use our own light color, otherwise dark 228 | final float[] hsv = new float[3]; 229 | Color.colorToHSV(themeColorBackground, hsv); 230 | backgroundColor = hsv[2] > 0.5f 231 | ? getResources().getColor(R.color.yc_cardview_light_background) 232 | : getResources().getColor(R.color.yc_cardview_dark_background); 233 | } 234 | startShadowColor = a.getColor(R.styleable.YcCardView_ycStartShadowColor, 0); 235 | endShadowColor = a.getColor(R.styleable.YcCardView_ycEndShadowColor, 0); 236 | float radius = a.getDimension(R.styleable.YcCardView_ycCardCornerRadius, 0); 237 | float elevation = a.getDimension(R.styleable.YcCardView_ycCardElevation, 0); 238 | float maxElevation = a.getDimension(R.styleable.YcCardView_ycCardMaxElevation, 0); 239 | mCompatPadding = a.getBoolean(R.styleable.YcCardView_ycCardUseCompatPadding, false); 240 | mPreventCornerOverlap = a.getBoolean(R.styleable.YcCardView_ycCardPreventCornerOverlap, true); 241 | int defaultPadding = a.getDimensionPixelSize(R.styleable.YcCardView_ycContentPadding, 0); 242 | mContentPadding.left = a.getDimensionPixelSize(R.styleable.YcCardView_ycContentPaddingLeft, 243 | defaultPadding); 244 | mContentPadding.top = a.getDimensionPixelSize(R.styleable.YcCardView_ycContentPaddingTop, 245 | defaultPadding); 246 | mContentPadding.right = a.getDimensionPixelSize(R.styleable.YcCardView_ycContentPaddingRight, 247 | defaultPadding); 248 | mContentPadding.bottom = a.getDimensionPixelSize(R.styleable.YcCardView_contentPaddingBottom, 249 | defaultPadding); 250 | if (elevation > maxElevation) { 251 | maxElevation = elevation; 252 | } 253 | mUserSetMinWidth = a.getDimensionPixelSize(R.styleable.YcCardView_android_minWidth, 0); 254 | mUserSetMinHeight = a.getDimensionPixelSize(R.styleable.YcCardView_android_minHeight, 0); 255 | a.recycle(); 256 | 257 | IMPL.initialize(mCardViewDelegate, context, backgroundColor, radius, 258 | elevation, maxElevation, startShadowColor, endShadowColor); 259 | } 260 | 261 | @Override 262 | public void setMinimumWidth(int minWidth) { 263 | mUserSetMinWidth = minWidth; 264 | super.setMinimumWidth(minWidth); 265 | } 266 | 267 | @Override 268 | public void setMinimumHeight(int minHeight) { 269 | mUserSetMinHeight = minHeight; 270 | super.setMinimumHeight(minHeight); 271 | } 272 | 273 | /** 274 | * Updates the background color of the CardView 275 | * 276 | * @param color The new color to set for the card background 277 | * ref com.zyp.cardview.R.styleable#YcCardView_cardBackgroundColor 278 | */ 279 | public void setCardBackgroundColor(int color) { 280 | IMPL.setBackgroundColor(mCardViewDelegate, color); 281 | } 282 | 283 | /** 284 | * Returns the inner padding after the Card's left edge 285 | * 286 | * @return the inner padding after the Card's left edge 287 | */ 288 | public int getContentPaddingLeft() { 289 | return mContentPadding.left; 290 | } 291 | 292 | /** 293 | * Returns the inner padding before the Card's right edge 294 | * 295 | * @return the inner padding before the Card's right edge 296 | */ 297 | public int getContentPaddingRight() { 298 | return mContentPadding.right; 299 | } 300 | 301 | /** 302 | * Returns the inner padding after the Card's top edge 303 | * 304 | * @return the inner padding after the Card's top edge 305 | */ 306 | public int getContentPaddingTop() { 307 | return mContentPadding.top; 308 | } 309 | 310 | /** 311 | * Returns the inner padding before the Card's bottom edge 312 | * 313 | * @return the inner padding before the Card's bottom edge 314 | */ 315 | public int getContentPaddingBottom() { 316 | return mContentPadding.bottom; 317 | } 318 | 319 | /** 320 | * Updates the corner radius of the CardView. 321 | * 322 | * @param radius The radius in pixels of the corners of the rectangle shape 323 | * ref com.zyp.cardview.R.styleable#YcCardView_cardCornerRadius 324 | * @see #setRadius(float) 325 | */ 326 | public void setRadius(float radius) { 327 | IMPL.setRadius(mCardViewDelegate, radius); 328 | } 329 | 330 | /** 331 | * Returns the corner radius of the CardView. 332 | * 333 | * @return Corner radius of the CardView 334 | * @see #getRadius() 335 | */ 336 | public float getRadius() { 337 | return IMPL.getRadius(mCardViewDelegate); 338 | } 339 | 340 | /** 341 | * Updates the backward compatible elevation of the CardView. 342 | * 343 | * @param elevation The backward compatible elevation in pixels. 344 | * ref com.zyp.cardview.R.styleable#YcCardView_cardElevation 345 | * @see #getCardElevation() 346 | * @see #setMaxCardElevation(float) 347 | */ 348 | public void setCardElevation(float elevation) { 349 | IMPL.setElevation(mCardViewDelegate, elevation); 350 | } 351 | 352 | /** 353 | * Returns the backward compatible elevation of the CardView. 354 | * 355 | * @return Elevation of the CardView 356 | * @see #setCardElevation(float) 357 | * @see #getMaxCardElevation() 358 | */ 359 | public float getCardElevation() { 360 | return IMPL.getElevation(mCardViewDelegate); 361 | } 362 | 363 | /** 364 | * Updates the backward compatible maximum elevation of the CardView. 365 | *
366 | * Calling this method has no effect if device OS version is Lollipop or newer and
367 | * {@link #getUseCompatPadding()} is false.
368 | *
369 | * @param maxElevation The backward compatible maximum elevation in pixels.
370 | * ref com.zyp.cardview.R.styleable#YcCardView_cardMaxElevation
371 | * @see #setCardElevation(float)
372 | * @see #getMaxCardElevation()
373 | */
374 | public void setMaxCardElevation(float maxElevation) {
375 | IMPL.setMaxElevation(mCardViewDelegate, maxElevation);
376 | }
377 |
378 | /**
379 | * Returns the backward compatible maximum elevation of the CardView.
380 | *
381 | * @return Maximum elevation of the CardView
382 | * @see #setMaxCardElevation(float)
383 | * @see #getCardElevation()
384 | */
385 | public float getMaxCardElevation() {
386 | return IMPL.getMaxElevation(mCardViewDelegate);
387 | }
388 |
389 | /**
390 | * Returns whether CardView should add extra padding to content to avoid overlaps with rounded
391 | * corners on pre-Lollipop platforms.
392 | *
393 | * @return True if CardView prevents overlaps with rounded corners on platforms before Lollipop.
394 | * Default value is true.
395 | */
396 | public boolean getPreventCornerOverlap() {
397 | return mPreventCornerOverlap;
398 | }
399 |
400 | /**
401 | * On pre-Lollipop platforms, CardView does not clip the bounds of the Card for the rounded
402 | * corners. Instead, it adds padding to content so that it won't overlap with the rounded
403 | * corners. You can disable this behavior by setting this field to false.
404 | *
405 | * Setting this value on Lollipop and above does not have any effect unless you have enabled 406 | * compatibility padding. 407 | * 408 | * @param preventCornerOverlap Whether CardView should add extra padding to content to avoid 409 | * overlaps with the CardView corners. 410 | * ref com.zyp.cardview.R.styleable#YcCardView_cardPreventCornerOverlap 411 | * @see #setUseCompatPadding(boolean) 412 | */ 413 | public void setPreventCornerOverlap(boolean preventCornerOverlap) { 414 | if (preventCornerOverlap != mPreventCornerOverlap) { 415 | mPreventCornerOverlap = preventCornerOverlap; 416 | IMPL.onPreventCornerOverlapChanged(mCardViewDelegate); 417 | } 418 | } 419 | 420 | private final YcCardViewDelegate mCardViewDelegate = new YcCardViewDelegate() { 421 | private Drawable mCardBackground; 422 | 423 | @Override 424 | public void setCardBackground(Drawable drawable) { 425 | mCardBackground = drawable; 426 | setBackgroundDrawable(drawable); 427 | } 428 | 429 | @Override 430 | public boolean getUseCompatPadding() { 431 | return YcCardView.this.getUseCompatPadding(); 432 | } 433 | 434 | @Override 435 | public boolean getPreventCornerOverlap() { 436 | return YcCardView.this.getPreventCornerOverlap(); 437 | } 438 | 439 | @Override 440 | public void setShadowPadding(int left, int top, int right, int bottom) { 441 | mShadowBounds.set(left, top, right, bottom); 442 | YcCardView.super.setPadding(left + mContentPadding.left, top + mContentPadding.top, 443 | right + mContentPadding.right, bottom + mContentPadding.bottom); 444 | } 445 | 446 | @Override 447 | public void setMinWidthHeightInternal(int width, int height) { 448 | if (width > mUserSetMinWidth) { 449 | YcCardView.super.setMinimumWidth(width); 450 | } 451 | if (height > mUserSetMinHeight) { 452 | YcCardView.super.setMinimumHeight(height); 453 | } 454 | } 455 | 456 | @Override 457 | public Drawable getCardBackground() { 458 | return mCardBackground; 459 | } 460 | 461 | @Override 462 | public View getCardView() { 463 | return YcCardView.this; 464 | } 465 | }; 466 | } 467 | --------------------------------------------------------------------------------