今天改需求改的我头疼,最可气的是,测试悠哉游哉的跑过来,丢下一句"哟,又写BUG呢?",我一想我也不是惯孩子人啊?当时我就回了一句,"正写着呢?要不晚上一块儿加班啊?请你吃好吃的",这货竟然说"行啊!"吃货的世界真的不懂!可是真心说一句,改需求能不能不这么从容,每次都是立刻上线了,淡定的丢下一句,不行改改吧!个人内心是这样的。。。 android
好吧!!!原谅个人放纵,被公司看见会不会被打死???我要去看个人秘籍了。。。程序员
好了不扯淡了!canvas
CardView是google在5.0中提供带圆角和阴影的布局,继承自FrameLayout。bash
能设置的属性就这么多了,没有什么好说的。可是最后两个属性会在后面的时候详细讲解,涉及到相应的适配!app
其实在平时的开发中,若是不考虑适配的话,CardView使用起来是很简单,可是提及适配的话,感受真心头疼。我第一次用CardView的时候,弄适配弄了两个多消失,当时以为天都是黑的!!!先看简单的效果吧。。。ide
<android.support.v7.widget.CardView
android:id="@+id/cv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:cardBackgroundColor="#c4c6c8"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:cardPreventCornerOverlap="true"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/heard_1" />
</android.support.v7.widget.CardView>
复制代码
效果是这个样子的。。。布局
注意啊这个是5.0以上的手机拍的,它默认帮咱们把圆角裁剪了(若是你设置了圆角的话)。按照上面的属性进行设置就能够了!测试
这个才是本片文章的重点问题!若是没有作过适配的人,会以为CardView很简单的。可是若是让你适配的话,你就。。。先来看一张照片!ui
重点的地方,我都标记出来了,若是大家产品和美工能容忍的话。那只能说你跟他们有一腿!this
图片上下左右的边距比较好处理,由于上面提到了两个属性
app:cardUseCompatPadding="true"
app:cardPreventCornerOverlap="false"
复制代码
内边距是不见了,可是圆角的处理就成了接下来的问题了。
最开始我觉得设置上面两个属性就能轻松的设置圆角了呢?太相信谷歌了。而后个人想法就是找一个处理圆角的控件,可是找了很久,基本上都是处理四个圆角的,没有单个圆角的处理,当时产品的意思是只处理左边的两个圆角。好吧,继续找,最后中于找到了。当时给你们发个福利了!哈哈,我真的不知道怎么上传相应的文件。原谅个人无知!
public class SelectableRoundedImageView extends ImageView {
public static final String TAG = "SelectableRoundedImageView";
private int mResource = 0;
private static final ScaleType[] sScaleTypeArray = {
ScaleType.MATRIX,
ScaleType.FIT_XY,
ScaleType.FIT_START,
ScaleType.FIT_CENTER,
ScaleType.FIT_END,
ScaleType.CENTER,
ScaleType.CENTER_CROP,
ScaleType.CENTER_INSIDE
};
// Set default scale type to FIT_CENTER, which is default scale type of
// original ImageView.
private ScaleType mScaleType = ScaleType.FIT_CENTER;
private float mLeftTopCornerRadius = 0.0f;
private float mRightTopCornerRadius = 0.0f;
private float mLeftBottomCornerRadius = 0.0f;
private float mRightBottomCornerRadius = 0.0f;
private float mBorderWidth = 0.0f;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
private boolean isOval = false;
private Drawable mDrawable;
private float[] mRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 };
public SelectableRoundedImageView(Context context) {
super(context);
}
public SelectableRoundedImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SelectableRoundedImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SelectableRoundedImageView, defStyle, 0);
final int index = a.getInt(R.styleable.SelectableRoundedImageView_android_scaleType, -1);
if (index >= 0) {
setScaleType(sScaleTypeArray[index]);
}
mLeftTopCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_left_top_corner_radius, 0);
mRightTopCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_right_top_corner_radius, 0);
mLeftBottomCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_left_bottom_corner_radius, 0);
mRightBottomCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_right_bottom_corner_radius, 0);
if (mLeftTopCornerRadius < 0.0f || mRightTopCornerRadius < 0.0f
|| mLeftBottomCornerRadius < 0.0f || mRightBottomCornerRadius < 0.0f) {
throw new IllegalArgumentException("radius values cannot be negative.");
}
mRadii = new float[] {
mLeftTopCornerRadius, mLeftTopCornerRadius,
mRightTopCornerRadius, mRightTopCornerRadius,
mRightBottomCornerRadius, mRightBottomCornerRadius,
mLeftBottomCornerRadius, mLeftBottomCornerRadius };
mBorderWidth = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_border_width, 0);
if (mBorderWidth < 0) {
throw new IllegalArgumentException("border width cannot be negative.");
}
mBorderColor = a
.getColorStateList(R.styleable.SelectableRoundedImageView_sriv_border_color);
if (mBorderColor == null) {
mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
}
isOval = a.getBoolean(R.styleable.SelectableRoundedImageView_sriv_oval, false);
a.recycle();
updateDrawable();
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
invalidate();
}
@Override
public ScaleType getScaleType() {
return mScaleType;
}
@Override
public void setScaleType(ScaleType scaleType) {
super.setScaleType(scaleType);
mScaleType = scaleType;
updateDrawable();
}
@Override
public void setImageDrawable(Drawable drawable) {
mResource = 0;
mDrawable = SelectableRoundedCornerDrawable.fromDrawable(drawable, getResources());
super.setImageDrawable(mDrawable);
updateDrawable();
}
@Override
public void setImageBitmap(Bitmap bm) {
mResource = 0;
mDrawable = SelectableRoundedCornerDrawable.fromBitmap(bm, getResources());
super.setImageDrawable(mDrawable);
updateDrawable();
}
@Override
public void setImageResource(int resId) {
if (mResource != resId) {
mResource = resId;
mDrawable = resolveResource();
super.setImageDrawable(mDrawable);
updateDrawable();
}
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
setImageDrawable(getDrawable());
}
private Drawable resolveResource() {
Resources rsrc = getResources();
if (rsrc == null) {
return null;
}
Drawable d = null;
if (mResource != 0) {
try {
d = rsrc.getDrawable(mResource);
} catch (NotFoundException e) {
// Don't try again. mResource = 0; } } return SelectableRoundedCornerDrawable.fromDrawable(d, getResources()); } private void updateDrawable() { if (mDrawable == null) { return; } ((SelectableRoundedCornerDrawable) mDrawable).setScaleType(mScaleType); ((SelectableRoundedCornerDrawable) mDrawable).setCornerRadii(mRadii); ((SelectableRoundedCornerDrawable) mDrawable).setBorderWidth(mBorderWidth); ((SelectableRoundedCornerDrawable) mDrawable).setBorderColor(mBorderColor); ((SelectableRoundedCornerDrawable) mDrawable).setOval(isOval); } public float getCornerRadius() { return mLeftTopCornerRadius; } /** * Set radii for each corner. * * @param leftTop The desired radius for left-top corner in dip. * @param rightTop The desired desired radius for right-top corner in dip. * @param leftBottom The desired radius for left-bottom corner in dip. * @param rightBottom The desired radius for right-bottom corner in dip. * */ public void setCornerRadiiDP(float leftTop, float rightTop, float leftBottom, float rightBottom) { final float density = getResources().getDisplayMetrics().density; final float lt = leftTop * density; final float rt = rightTop * density; final float lb = leftBottom * density; final float rb = rightBottom * density; mRadii = new float[] { lt, lt, rt, rt, rb, rb, lb, lb }; updateDrawable(); } public float getBorderWidth() { return mBorderWidth; } /** * Set border width. * * @param width * The desired width in dip. */ public void setBorderWidthDP(float width) { float scaledWidth = getResources().getDisplayMetrics().density * width; if (mBorderWidth == scaledWidth) { return; } mBorderWidth = scaledWidth; updateDrawable(); invalidate(); } public int getBorderColor() { return mBorderColor.getDefaultColor(); } public void setBorderColor(int color) { setBorderColor(ColorStateList.valueOf(color)); } public ColorStateList getBorderColors() { return mBorderColor; } public void setBorderColor(ColorStateList colors) { if (mBorderColor.equals(colors)) { return; } mBorderColor = (colors != null) ? colors : ColorStateList .valueOf(DEFAULT_BORDER_COLOR); updateDrawable(); if (mBorderWidth > 0) { invalidate(); } } public boolean isOval() { return isOval; } public void setOval(boolean oval) { isOval = oval; updateDrawable(); invalidate(); } static class SelectableRoundedCornerDrawable extends Drawable { private static final String TAG = "SelectableRoundedCornerDrawable"; private static final int DEFAULT_BORDER_COLOR = Color.BLACK; private RectF mBounds = new RectF(); private RectF mBorderBounds = new RectF(); private final RectF mBitmapRect = new RectF(); private final int mBitmapWidth; private final int mBitmapHeight; private final Paint mBitmapPaint; private final Paint mBorderPaint; private BitmapShader mBitmapShader; private float[] mRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 }; private float[] mBorderRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 }; private boolean mOval = false; private float mBorderWidth = 0; private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR); // Set default scale type to FIT_CENTER, which is default scale type of // original ImageView. private ScaleType mScaleType = ScaleType.FIT_CENTER; private Path mPath = new Path(); private Bitmap mBitmap; private boolean mBoundsConfigured = false; public SelectableRoundedCornerDrawable(Bitmap bitmap, Resources r) { mBitmap = bitmap; mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); if (bitmap != null) { mBitmapWidth = bitmap.getScaledWidth(r.getDisplayMetrics()); mBitmapHeight = bitmap.getScaledHeight(r.getDisplayMetrics()); } else { mBitmapWidth = mBitmapHeight = -1; } mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight); mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBitmapPaint.setStyle(Paint.Style.FILL); mBitmapPaint.setShader(mBitmapShader); mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR)); mBorderPaint.setStrokeWidth(mBorderWidth); } public static SelectableRoundedCornerDrawable fromBitmap(Bitmap bitmap, Resources r) { if (bitmap != null) { return new SelectableRoundedCornerDrawable(bitmap, r); } else { return null; } } public static Drawable fromDrawable(Drawable drawable, Resources r) { if (drawable != null) { if (drawable instanceof SelectableRoundedCornerDrawable) { return drawable; } else if (drawable instanceof LayerDrawable) { LayerDrawable ld = (LayerDrawable) drawable; final int num = ld.getNumberOfLayers(); for (int i = 0; i < num; i++) { Drawable d = ld.getDrawable(i); ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d, r)); } return ld; } Bitmap bm = drawableToBitmap(drawable); if (bm != null) { return new SelectableRoundedCornerDrawable(bm, r); } else { } } return drawable; } public static Bitmap drawableToBitmap(Drawable drawable) { if (drawable == null) { return null; } if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } Bitmap bitmap; int width = Math.max(drawable.getIntrinsicWidth(), 2); int height = Math.max(drawable.getIntrinsicHeight(), 2); try { bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); } catch (IllegalArgumentException e) { e.printStackTrace(); bitmap = null; } return bitmap; } @Override public boolean isStateful() { return mBorderColor.isStateful(); } @Override protected boolean onStateChange(int[] state) { int newColor = mBorderColor.getColorForState(state, 0); if (mBorderPaint.getColor() != newColor) { mBorderPaint.setColor(newColor); return true; } else { return super.onStateChange(state); } } private void configureBounds(Canvas canvas) { // I have discovered a truly marvelous explanation of this, // which this comment space is too narrow to contain. :) // If you want to understand what's going on here,
// See http://www.joooooooooonhokim.com/?p=289
Rect clipBounds = canvas.getClipBounds();
Matrix canvasMatrix = canvas.getMatrix();
if (ScaleType.CENTER == mScaleType) {
mBounds.set(clipBounds);
} else if (ScaleType.CENTER_CROP == mScaleType) {
applyScaleToRadii(canvasMatrix);
mBounds.set(clipBounds);
} else if (ScaleType.FIT_XY == mScaleType) {
Matrix m = new Matrix();
m.setRectToRect(mBitmapRect, new RectF(clipBounds), Matrix.ScaleToFit.FILL);
mBitmapShader.setLocalMatrix(m);
mBounds.set(clipBounds);
} else if (ScaleType.FIT_START == mScaleType || ScaleType.FIT_END == mScaleType
|| ScaleType.FIT_CENTER == mScaleType || ScaleType.CENTER_INSIDE == mScaleType) {
applyScaleToRadii(canvasMatrix);
mBounds.set(mBitmapRect);
} else if (ScaleType.MATRIX == mScaleType) {
applyScaleToRadii(canvasMatrix);
mBounds.set(mBitmapRect);
}
}
private void applyScaleToRadii(Matrix m) {
float[] values = new float[9];
m.getValues(values);
for (int i = 0; i < mRadii.length; i++) {
mRadii[i] = mRadii[i] / values[0];
}
}
private void adjustCanvasForBorder(Canvas canvas) {
Matrix canvasMatrix = canvas.getMatrix();
final float[] values = new float[9];
canvasMatrix.getValues(values);
final float scaleFactorX = values[0];
final float scaleFactorY = values[4];
final float translateX = values[2];
final float translateY = values[5];
final float newScaleX = mBounds.width()
/ (mBounds.width() + mBorderWidth + mBorderWidth);
final float newScaleY = mBounds.height()
/ (mBounds.height() + mBorderWidth + mBorderWidth);
canvas.scale(newScaleX, newScaleY);
if (ScaleType.FIT_START == mScaleType || ScaleType.FIT_END == mScaleType
|| ScaleType.FIT_XY == mScaleType || ScaleType.FIT_CENTER == mScaleType
|| ScaleType.CENTER_INSIDE == mScaleType || ScaleType.MATRIX == mScaleType) {
canvas.translate(mBorderWidth, mBorderWidth);
} else if (ScaleType.CENTER == mScaleType || ScaleType.CENTER_CROP == mScaleType) {
// First, make translate values to 0
canvas.translate(
-translateX / (newScaleX * scaleFactorX),
-translateY / (newScaleY * scaleFactorY));
// Then, set the final translate values.
canvas.translate(-(mBounds.left - mBorderWidth), -(mBounds.top - mBorderWidth));
}
}
private void adjustBorderWidthAndBorderBounds(Canvas canvas) {
Matrix canvasMatrix = canvas.getMatrix();
final float[] values = new float[9];
canvasMatrix.getValues(values);
final float scaleFactor = values[0];
float viewWidth = mBounds.width() * scaleFactor;
mBorderWidth = (mBorderWidth * mBounds.width()) / (viewWidth - (2 * mBorderWidth));
mBorderPaint.setStrokeWidth(mBorderWidth);
mBorderBounds.set(mBounds);
mBorderBounds.inset(- mBorderWidth / 2, - mBorderWidth / 2);
}
private void setBorderRadii() {
for (int i = 0; i < mRadii.length; i++) {
if (mRadii[i] > 0) {
mBorderRadii[i] = mRadii[i];
mRadii[i] = mRadii[i] - mBorderWidth;
}
}
}
@Override
public void draw(Canvas canvas) {
canvas.save();
if (!mBoundsConfigured) {
configureBounds(canvas);
if (mBorderWidth > 0) {
adjustBorderWidthAndBorderBounds(canvas);
setBorderRadii();
}
mBoundsConfigured = true;
}
if (mOval) {
if (mBorderWidth > 0) {
adjustCanvasForBorder(canvas);
mPath.addOval(mBounds, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
mPath.reset();
mPath.addOval(mBorderBounds, Path.Direction.CW);
canvas.drawPath(mPath, mBorderPaint);
} else {
mPath.addOval(mBounds, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
}
} else {
if (mBorderWidth > 0) {
adjustCanvasForBorder(canvas);
mPath.addRoundRect(mBounds, mRadii, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
mPath.reset();
mPath.addRoundRect(mBorderBounds, mBorderRadii, Path.Direction.CW);
canvas.drawPath(mPath, mBorderPaint);
} else {
mPath.addRoundRect(mBounds, mRadii, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
}
}
canvas.restore();
}
public void setCornerRadii(float[] radii) {
if (radii == null)
return;
if (radii.length != 8) {
throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
}
for (int i = 0; i < radii.length; i++) {
mRadii[i] = radii[i];
}
}
@Override
public int getOpacity() {
return (mBitmap == null || mBitmap.hasAlpha() || mBitmapPaint.getAlpha() < 255) ? PixelFormat.TRANSLUCENT
: PixelFormat.OPAQUE;
}
@Override
public void setAlpha(int alpha) {
mBitmapPaint.setAlpha(alpha);
invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf) {
mBitmapPaint.setColorFilter(cf);
invalidateSelf();
}
@Override
public void setDither(boolean dither) {
mBitmapPaint.setDither(dither);
invalidateSelf();
}
@Override
public void setFilterBitmap(boolean filter) {
mBitmapPaint.setFilterBitmap(filter);
invalidateSelf();
}
@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
public float getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(float width) {
mBorderWidth = width;
mBorderPaint.setStrokeWidth(width);
}
public int getBorderColor() {
return mBorderColor.getDefaultColor();
}
public void setBorderColor(int color) {
setBorderColor(ColorStateList.valueOf(color));
}
public ColorStateList getBorderColors() {
return mBorderColor;
}
/**
* Controls border color of this ImageView.
*
* @param colors
* The desired border color. If it's null, no border will be * drawn. * */ public void setBorderColor(ColorStateList colors) { if (colors == null) { mBorderWidth = 0; mBorderColor = ColorStateList.valueOf(Color.TRANSPARENT); mBorderPaint.setColor(Color.TRANSPARENT); } else { mBorderColor = colors; mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR)); } } public boolean isOval() { return mOval; } public void setOval(boolean oval) { mOval = oval; } public ScaleType getScaleType() { return mScaleType; } public void setScaleType(ScaleType scaleType) { if (scaleType == null) { return; } mScaleType = scaleType; } } } 复制代码
自定义属性
<declare-styleable name="SelectableRoundedImageView">
<attr name="sriv_left_top_corner_radius" format="dimension"/>
<attr name="sriv_right_top_corner_radius" format="dimension"/>
<attr name="sriv_left_bottom_corner_radius" format="dimension"/>
<attr name="sriv_right_bottom_corner_radius" format="dimension"/>
<attr name="sriv_border_width" format="dimension"/>
<attr name="sriv_border_color" format="color"/>
<attr name="sriv_oval" format="boolean"/>
<attr name="android:scaleType"/>
</declare-styleable>
复制代码
也忘记是哪位大神些的了,在这里谢谢做者的开源精神!使用的时候直接设置相应的边角就能够了!仍是很方便的。。。今天就到这里吧,我可把我压箱底的东西都拿出来了,但愿对你有帮助!好了,今天就到这里了,See You!!!