Android 打造一款逼格高的圆形图片
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.widget.ImageView; import com.tcrj.example.activity.R; /** * 头像 * Created by leict on 2017/6/14. */ public class CircleImageView extends ImageView { private int outCiecleColor = Color.WHITE; private int outCiecleWidth; private Paint paintBorder; private int viewWidth; private int viewHeight; private Bitmap bitmap; public CircleImageView(Context context) { super(context); initAttrs(context, null); } public CircleImageView(Context context, AttributeSet attrs) { super(context, attrs); initAttrs(context, attrs); } public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initAttrs(context, attrs); } private void initAttrs(Context context, AttributeSet attrs) { if (attrs != null) { TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CiecleImageView); int len = array.length(); for (int i = 0; i < len; i++) { int attr = array.getIndex(i); switch (attr) { case R.styleable.CiecleImageView_outCiecleColor: this.outCiecleColor = array.getColor(attr, Color.WHITE); break; case R.styleable.CiecleImageView_outCiecleWidth: this.outCiecleWidth = (int) array.getDimension(attr, 5); break; } } } paintBorder = new Paint(); paintBorder.setColor(outCiecleColor); paintBorder.setAntiAlias(true); } /** * 测量 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = measuredWidth(widthMeasureSpec); int height = measuredHeight(heightMeasureSpec); viewWidth = width - (outCiecleWidth * 2); viewHeight = height - (outCiecleWidth * 2); setMeasuredDimension(width, height); } /** * 加载图片 */ private void loadImage() { BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable(); if (bitmapDrawable != null) { bitmap = bitmapDrawable.getBitmap(); } } @Override protected void onDraw(Canvas canvas) { loadImage(); if (bitmap != null) { int min = Math.min(viewHeight, viewWidth); int ciecleCenter = min / 2; bitmap = Bitmap.createScaledBitmap(bitmap, min, min, false); canvas.drawCircle(ciecleCenter + outCiecleWidth, ciecleCenter + outCiecleWidth, ciecleCenter + outCiecleWidth, paintBorder); canvas.drawBitmap(createCiecleBitmap(bitmap, min), outCiecleWidth, outCiecleWidth, null); } } /** * 创建一个圆形的Bitmap * * @param image * @param min * @return */ private Bitmap createCiecleBitmap(Bitmap image, int min) { Bitmap mBitmap = null; Paint mPaint = new Paint(); mPaint.setAntiAlias(true); mBitmap = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(mBitmap); canvas.drawCircle(min / 2, min / 2, min / 2, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(image, 0, 0, mPaint); return mBitmap; } /** * 测量宽度 * * @param widthMeasureSpec * @return */ private int measuredWidth(int widthMeasureSpec) { int result = 0; int mode = MeasureSpec.getMode(widthMeasureSpec); int size = MeasureSpec.getSize(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { result = viewWidth; } return result; } /** * 测量高度 * * @param heightMeasureSpec * @return */ private int measuredHeight(int heightMeasureSpec) { int result = 0; int mode = MeasureSpec.getMode(heightMeasureSpec); int size = MeasureSpec.getSize(heightMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { result = viewHeight; } return result; } /** * 动态设置颜色 * * @param color */ public void setBorderColor(int color) { if (paintBorder != null) { paintBorder.setColor(color); } this.invalidate(); } /** * 动态设置宽度 * * @param width */ public void setBorderWidth(int width) { this.outCiecleWidth = width; this.invalidate(); } }
在value文件夹下新建一个attrs文件:
1 2 3 4 5 6 7 | <?xml version= "1.0" encoding= "utf-8" ?> <resources> <declare-styleable name= "CiecleImageView" > <attr name= "outCiecleColor" format= "color" ></attr> <attr name= "outCiecleWidth" format= "dimension" ></attr> </declare-styleable> </resources> |
XML文件布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="@dimen/height_10" android:orientation="vertical"> <com.tcrj.example.image.CircleImageView android:id="@+id/imgview" android:layout_width="200dp" android:layout_height="200dp" android:src="@mipmap/face4" /> </LinearLayout>
动态设置表框的宽度及颜色:
imgview = (CircleImageView) findViewById(R.id.imgview);
imgview.setBorderColor(Color.RED);
imgview.setBorderWidth(10);
效果图如下:

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】