
Android 圆图 带圆角的图 头像图
发布日期:2021-05-07 18:54:12
浏览次数:25
分类:原创文章
本文共 13039 字,大约阅读时间需要 43 分钟。
用到了第三方插件,
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" />
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年04月02日 15时39分22秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
算法学习笔记: 珂朵莉树
2021-05-09
算法学习笔记:母函数详解
2021-05-09
Codeforces Round #664 题解(A ~ C)
2021-05-09
Problem A - Sequence with Digits (数学推导)
2021-05-09
Problem 330A - Cakeminator (思维)
2021-05-09
LeetCode75 颜色分类 (三路快排C++实现与应用)
2021-05-09
docker基础:容器生命周期管理命令
2021-05-09
Shell脚本学习指南
2021-05-09
C#开发BIMFACE系列35 服务端API之模型对比6:获取模型构建对比分类树
2021-05-09
C# 规范建议
2021-05-09
C语言+easyX图形库的推箱子实现
2021-05-09
反汇编-流程控制语句-2-循环控制语句分析
2021-05-09
调试vs2019代码的流程
2021-05-09
游戏外挂基础-概述
2021-05-09
脱壳与加壳-加壳-6-代码实现加密导入表
2021-05-09
Typora配置PicGo时,提示Failed to fetch
2021-05-09
ASP.NET CORE MVC 实现减号分隔(Kebab case)样式的 URL
2021-05-09
SQL优化 MySQL版 -分析explain SQL执行计划与笛卡尔积
2021-05-09
bcolz的新操作
2021-05-09
Linux的s、t、i、a权限(转)
2021-05-09