用到了第三方插件,
NiceImageView
感興趣可以去git搜一下。。
源碼如下
package com.anguomob.love.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import com.anguomob.love.R;
public class NiceImageView extends AppCompatImageView {
private Context context;
private boolean isCircle; // 是否顯示爲圓形,如果爲圓形則設置的corner無效
private boolean isCoverSrc; // border、inner_border是否覆蓋圖片
private int borderWidth; // 邊框寬度
private int borderColor = Color.WHITE; // 邊框顏色
private int innerBorderWidth; // 內層邊框寬度
private int innerBorderColor = Color.WHITE; // 內層邊框充色
private int cornerRadius; // 統一設置圓角半徑,優先級高於單獨設置每個角的半徑
private int cornerTopLeftRadius; // 左上角圓角半徑
private int cornerTopRightRadius; // 右上角圓角半徑
private int cornerBottomLeftRadius; // 左下角圓角半徑
private int cornerBottomRightRadius; // 右下角圓角半徑
private int maskColor; // 遮罩顏色
private Xfermode xfermode;
private int width;
private int height;
private float radius;
private float[] borderRadii;
private float[] srcRadii;
private RectF srcRectF; // 圖片佔的矩形區域
private RectF borderRectF; // 邊框的矩形區域
private Paint paint;
private Path path; // 用來裁剪圖片的ptah
private Path srcPath; // 圖片區域大小的path
public NiceImageView(Context context) {
this(context, null);
}
public NiceImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public NiceImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.NiceImageView, 0, 0);
for (int i = 0; i < ta.getIndexCount(); i++) {
int attr = ta.getIndex(i);
if (attr == R.styleable.NiceImageView_niv_is_cover_src) {
isCoverSrc = ta.getBoolean(attr, isCoverSrc);
} else if (attr == R.styleable.NiceImageView_niv_is_circle) {
isCircle = ta.getBoolean(attr, isCircle);
} else if (attr == R.styleable.NiceImageView_niv_border_width) {
borderWidth = ta.getDimensionPixelSize(attr, borderWidth);
} else if (attr == R.styleable.NiceImageView_niv_border_color) {
borderColor = ta.getColor(attr, borderColor);
} else if (attr == R.styleable.NiceImageView_niv_inner_border_width) {
innerBorderWidth = ta.getDimensionPixelSize(attr, innerBorderWidth);
} else if (attr == R.styleable.NiceImageView_niv_inner_border_color) {
innerBorderColor = ta.getColor(attr, innerBorderColor);
} else if (attr == R.styleable.NiceImageView_niv_corner_radius) {
cornerRadius = ta.getDimensionPixelSize(attr, cornerRadius);
} else if (attr == R.styleable.NiceImageView_niv_corner_top_left_radius) {
cornerTopLeftRadius = ta.getDimensionPixelSize(attr, cornerTopLeftRadius);
} else if (attr == R.styleable.NiceImageView_niv_corner_top_right_radius) {
cornerTopRightRadius = ta.getDimensionPixelSize(attr, cornerTopRightRadius);
} else if (attr == R.styleable.NiceImageView_niv_corner_bottom_left_radius) {
cornerBottomLeftRadius = ta.getDimensionPixelSize(attr, cornerBottomLeftRadius);
} else if (attr == R.styleable.NiceImageView_niv_corner_bottom_right_radius) {
cornerBottomRightRadius = ta.getDimensionPixelSize(attr, cornerBottomRightRadius);
} else if (attr == R.styleable.NiceImageView_niv_mask_color) {
maskColor = ta.getColor(attr, maskColor);
}
}
ta.recycle();
borderRadii = new float[8];
srcRadii = new float[8];
borderRectF = new RectF();
srcRectF = new RectF();
paint = new Paint();
path = new Path();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
} else {
xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
srcPath = new Path();
}
calculateRadii();
clearInnerBorderWidth();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
initBorderRectF();
initSrcRectF();
}
@Override
protected void onDraw(Canvas canvas) {
// 使用圖形混合模式來顯示指定區域的圖片
canvas.saveLayer(srcRectF, null, Canvas.ALL_SAVE_FLAG);
if (!isCoverSrc) {
float sx = 1.0f * (width - 2 * borderWidth - 2 * innerBorderWidth) / width;
float sy = 1.0f * (height - 2 * borderWidth - 2 * innerBorderWidth) / height;
// 縮小畫布,使圖片內容不被borders覆蓋
canvas.scale(sx, sy, width / 2.0f, height / 2.0f);
}
super.onDraw(canvas);
paint.reset();
path.reset();
if (isCircle) {
path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
} else {
path.addRoundRect(srcRectF, srcRadii, Path.Direction.CCW);
}
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paint.setXfermode(xfermode);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
canvas.drawPath(path, paint);
} else {
srcPath.reset();
srcPath.addRect(srcRectF, Path.Direction.CCW);
// 計算tempPath和path的差集
srcPath.op(path, Path.Op.DIFFERENCE);
canvas.drawPath(srcPath, paint);
}
paint.setXfermode(null);
// 繪製遮罩
if (maskColor != 0) {
paint.setColor(maskColor);
canvas.drawPath(path, paint);
}
// 恢復畫布
canvas.restore();
// 繪製邊框
drawBorders(canvas);
}
private void drawBorders(Canvas canvas) {
if (isCircle) {
if (borderWidth > 0) {
drawCircleBorder(canvas, borderWidth, borderColor, radius - borderWidth / 2.0f);
}
if (innerBorderWidth > 0) {
drawCircleBorder(canvas, innerBorderWidth, innerBorderColor,
radius - borderWidth - innerBorderWidth / 2.0f);
}
} else {
if (borderWidth > 0) {
drawRectFBorder(canvas, borderWidth, borderColor, borderRectF, borderRadii);
}
}
}
private void drawCircleBorder(Canvas canvas, int borderWidth, int borderColor, float radius) {
initBorderPaint(borderWidth, borderColor);
path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
canvas.drawPath(path, paint);
}
private void drawRectFBorder(Canvas canvas, int borderWidth, int borderColor, RectF rectF,
float[] radii) {
initBorderPaint(borderWidth, borderColor);
path.addRoundRect(rectF, radii, Path.Direction.CCW);
canvas.drawPath(path, paint);
}
private void initBorderPaint(int borderWidth, int borderColor) {
path.reset();
paint.setStrokeWidth(borderWidth);
paint.setColor(borderColor);
paint.setStyle(Paint.Style.STROKE);
}
/**
* 計算外邊框的RectF
*/
private void initBorderRectF() {
if (!isCircle) {
borderRectF.set(borderWidth / 2.0f, borderWidth / 2.0f, width - borderWidth / 2.0f,
height - borderWidth / 2.0f);
}
}
/**
* 計算圖片原始區域的RectF
*/
private void initSrcRectF() {
if (isCircle) {
radius = Math.min(width, height) / 2.0f;
srcRectF.set(width / 2.0f - radius, height / 2.0f - radius, width / 2.0f + radius,
height / 2.0f + radius);
} else {
srcRectF.set(0, 0, width, height);
if (isCoverSrc) {
srcRectF = borderRectF;
}
}
}
/**
* 計算RectF的圓角半徑
*/
private void calculateRadii() {
if (isCircle) {
return;
}
if (cornerRadius > 0) {
for (int i = 0; i < borderRadii.length; i++) {
borderRadii[i] = cornerRadius;
srcRadii[i] = cornerRadius - borderWidth / 2.0f;
}
} else {
borderRadii[0] = borderRadii[1] = cornerTopLeftRadius;
borderRadii[2] = borderRadii[3] = cornerTopRightRadius;
borderRadii[4] = borderRadii[5] = cornerBottomRightRadius;
borderRadii[6] = borderRadii[7] = cornerBottomLeftRadius;
srcRadii[0] = srcRadii[1] = cornerTopLeftRadius - borderWidth / 2.0f;
srcRadii[2] = srcRadii[3] = cornerTopRightRadius - borderWidth / 2.0f;
srcRadii[4] = srcRadii[5] = cornerBottomRightRadius - borderWidth / 2.0f;
srcRadii[6] = srcRadii[7] = cornerBottomLeftRadius - borderWidth / 2.0f;
}
}
private void calculateRadiiAndRectF(boolean reset) {
if (reset) {
cornerRadius = 0;
}
calculateRadii();
initBorderRectF();
invalidate();
}
/**
* 目前圓角矩形情況下不支持inner_border,需要將其置0
*/
private void clearInnerBorderWidth() {
if (!isCircle) {
this.innerBorderWidth = 0;
}
}
public void isCoverSrc(boolean isCoverSrc) {
this.isCoverSrc = isCoverSrc;
initSrcRectF();
invalidate();
}
public void isCircle(boolean isCircle) {
this.isCircle = isCircle;
clearInnerBorderWidth();
initSrcRectF();
invalidate();
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = dp2px(borderWidth);
calculateRadiiAndRectF(false);
}
public void setBorderColor(@ColorInt int borderColor) {
this.borderColor = borderColor;
invalidate();
}
public void setInnerBorderWidth(int innerBorderWidth) {
this.innerBorderWidth = dp2px(innerBorderWidth);
clearInnerBorderWidth();
invalidate();
}
public void setInnerBorderColor(@ColorInt int innerBorderColor) {
this.innerBorderColor = innerBorderColor;
invalidate();
}
public void setCornerRadius(int cornerRadius) {
this.cornerRadius = dp2px(cornerRadius);
calculateRadiiAndRectF(false);
}
public void setCornerTopLeftRadius(int cornerTopLeftRadius) {
this.cornerTopLeftRadius = dp2px(cornerTopLeftRadius);
calculateRadiiAndRectF(true);
}
public void setCornerTopRightRadius(int cornerTopRightRadius) {
this.cornerTopRightRadius = dp2px(cornerTopRightRadius);
calculateRadiiAndRectF(true);
}
public void setCornerBottomLeftRadius(int cornerBottomLeftRadius) {
this.cornerBottomLeftRadius = dp2px(cornerBottomLeftRadius);
calculateRadiiAndRectF(true);
}
public void setCornerBottomRightRadius(int cornerBottomRightRadius) {
this.cornerBottomRightRadius = dp2px(cornerBottomRightRadius);
calculateRadiiAndRectF(true);
}
public void setMaskColor(@ColorInt int maskColor) {
this.maskColor = maskColor;
invalidate();
}
private int dp2px(int dp) {
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
context.getResources().getDisplayMetrics()));
}
}
自定義樣式
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="NiceImageView">
<attr name="niv_is_circle" format="boolean" />
<attr name="niv_is_cover_src" format="boolean" />
<attr name="niv_corner_radius" format="dimension" />
<attr name="niv_corner_top_left_radius" format="dimension" />
<attr name="niv_corner_top_right_radius" format="dimension" />
<attr name="niv_corner_bottom_left_radius" format="dimension" />
<attr name="niv_corner_bottom_right_radius" format="dimension" />
<attr name="niv_border_width" format="dimension" />
<attr name="niv_border_color" format="color" />
<attr name="niv_inner_border_width" format="dimension" />
<attr name="niv_inner_border_color" format="color" />
<attr name="niv_mask_color" format="color" />
</declare-styleable>
</resources>
使用也很簡單
<com.anguomob.love.view.NiceImageView
android:id="@+id/mIvUpload"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@mipmap/ic_launcher"
android:textColor="@color/color_999999"
android:textSize="18sp"
android:visibility="gone"
app:niv_is_circle="true" />