Android自定义View之圆形头像
来源:互联网 发布:淘宝外卖系统繁忙 编辑:程序博客网 时间:2024/05/21 22:22
圆形头像是我们在开发中经常用到的控件,下面我们就来自定义这样一个控件:
1.自定义CircleImageView类继承ImageView
package com.example.qw.circleimageview;/** * Created by quwei on 2015/5/13 0013. */import android.content.Context;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.Rect;import android.graphics.RectF;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.util.Log;import android.widget.ImageView;public class CircleImageView extends ImageView { private static final String TAG = "vvv"; private Bitmap mask; private Paint paint; private Paint mBorderPaint; private int mBorderWidth = 2; private int mBorderColor = Color.BLUE; public CircleImageView(Context paramContext) { super(paramContext); } public CircleImageView(Context paramContext, AttributeSet paramAttributeSet) { this(paramContext, paramAttributeSet, 0); } public CircleImageView(Context context, AttributeSet paramAttributeSet, int paramInt) { super(context, paramAttributeSet, paramInt); TypedArray a = context.obtainStyledAttributes(paramAttributeSet, R.styleable.CircularImage); mBorderColor = a.getColor(R.styleable.CircularImage_border_color, mBorderColor);// float density = context.getResources().getDisplayMetrics().density; // 获取屏幕密度 mBorderWidth = a.getDimensionPixelOffset(R.styleable.CircularImage_border_width, 0); a.recycle(); } private boolean useDefaultStyle = false; public void setUseDefaultStyle(boolean useDefaultStyle) { this.useDefaultStyle = useDefaultStyle; } @Override protected void onDraw(Canvas canvas) { if (useDefaultStyle) { super.onDraw(canvas); return; } Drawable drawable = getDrawable(); if (drawable == null) { super.draw(canvas); return; } /** * 第一种方法,使用图层进行图片混合 */ Drawable localDrawable = editDrawable(drawable); drawCircleImage(canvas, localDrawable); /** * 第二种方法,创建新的画布,并在该画布上进行混合,生成混合后的bitmap, * 再将该bitmap画回到该View的原画布上 */// Bitmap src = ((BitmapDrawable) drawable).getBitmap();// Bitmap bitmap = createCircleImage(src);// canvas.drawBitmap(bitmap, 0, 0, null); // 对圆形图像进行描边 drawBorder(canvas, getWidth(), getHeight()); } private void drawCircleImage(Canvas canvas, Drawable localDrawable) { canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG); localDrawable.draw(canvas); if (mask == null) mask = createOvalBitmap(getWidth(), getHeight()); if (this.paint == null) { final Paint localPaint = new Paint(); localPaint.setFilterBitmap(false); localPaint.setAntiAlias(true); // 关键!DST_IN具体情况请查阅官方文档 localPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); this.paint = localPaint; } canvas.drawBitmap(mask, 0, 0, paint); canvas.restore(); } private void drawBorder(Canvas canvas, final int width, final int height) { if (mBorderWidth == 0) { return; } if (mBorderPaint == null) { mBorderPaint = new Paint(); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStrokeWidth(mBorderWidth); } RectF rectF = new RectF(0 + mBorderWidth, 0 + mBorderWidth, width - mBorderWidth, height - mBorderWidth); canvas.drawOval(rectF, mBorderPaint); } private Drawable editDrawable(Drawable localDrawable) { int drawableWidth = localDrawable.getIntrinsicWidth(); int drawableHeight = localDrawable.getIntrinsicHeight(); Log.i(TAG, "" + drawableWidth + "," + drawableHeight); final int width = getWidth(); final int height = getHeight(); Log.i(TAG, "" + width + "," + height); float rw = (float) drawableWidth / (float) width; float rh = (float) drawableHeight / (float) height; int dWidth; int dHeight; if (rw < rh) { dWidth = width; dHeight = (int) (drawableHeight / rw); //移动到中间的偏移量 int yOff = (dHeight - height) / 2; localDrawable.setBounds(0, -yOff, dWidth, dHeight - yOff); } else { dWidth = (int) (drawableWidth / rh); dHeight = height; int xOff = (dWidth - width) / 2; localDrawable.setBounds(-xOff, 0, dWidth - xOff, dHeight); } return localDrawable; } /** * 创建圆形画布 * * @param width * @param height * @return */ public Bitmap createOvalBitmap(final int width, final int height) { Bitmap localBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas localCanvas = new Canvas(localBitmap); Paint localPaint = new Paint(); localPaint.setColor(Color.GREEN); localPaint.setAntiAlias(true); // 很重要!设置抗锯齿 int padding = mBorderWidth; RectF localRectF = new RectF(padding, padding, width - padding, height - padding); localCanvas.drawOval(localRectF, localPaint); return localBitmap; } private Bitmap createCircleImage(Bitmap source) { Bitmap target = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); /** * 产生一个同样大小的画布 */ Canvas canvas = new Canvas(target); final Paint paint = new Paint(); paint.setAntiAlias(true); /** * 首先绘制圆形 */ int padding = mBorderWidth; RectF localRectF = new RectF(padding, padding, getWidth() - padding, getHeight() - padding); canvas.drawOval(localRectF, paint); /** * 使用SRC_IN */ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); /** * 绘制图片 */ int sourceWidth = source.getWidth(); int sourceHeight = source.getHeight(); Log.i(TAG, "sourceWidth:" + sourceWidth + ",sourceHeight:" + sourceHeight); final int width = getWidth(); final int height = getHeight(); Log.i(TAG, "width:" + width + ",height:" + height); float rw = (float) sourceWidth / (float) width; float rh = (float) sourceHeight / (float) height; int dWidth; int dHeight; if (rw < rh) { dWidth = width; dHeight = (int) (sourceHeight / rw); //移动到中间的偏移量 int yOff = (dHeight - height) / 2; canvas.drawBitmap(source, new Rect(0, 0, sourceWidth, sourceHeight), new Rect(0, -yOff, dWidth, dHeight - yOff), paint); } else { dWidth = (int) (sourceWidth / rh); dHeight = height; int xOff = (dWidth - width) / 2; canvas.drawBitmap(source, new Rect(0, 0, sourceWidth, sourceHeight), new Rect(-xOff, 0, dWidth - xOff, dHeight), paint); } Log.i(TAG, "dWidth:" + dWidth + ",dHeight:" + dHeight); return target; }}
代码没什么好说,有难度的地方都注释了
2.我们使用描边的时候自定义了属性,在value/atrr.xml文件中加上
<declare-styleable name="CircularImage"> <attr name="border_width" format="dimension" /> <attr name="border_color" format="color" /> </declare-styleable>
3.在布局文件中使用自定义View
<com.example.qw.circleimageview.CircleImageView xmlns:def="http://schemas.android.com/apk/res-auto" android:layout_width="150dp" android:layout_height="150dp" android:scaleType="centerCrop" android:src="@drawable/head" def:border_color="#F6170F" def:border_width="2dp" />
对混合模式有疑惑的请参考大神爱哥的博客:自定义控件其实很简单1/6
0 0
- Android自定义View之圆形头像
- Android 自定义View 之 圆形头像
- Android自定义View之圆形头像
- android圆形头像,自定义view
- Android 自定义View -->圆形头像
- android自定义view之圆形头像的完美例子
- Android-解析自定义view之圆形头像的各类方案
- android 之 自定义圆形头像
- 自定义view圆形头像
- android自定义圆形头像view,继承imageview
- Android圆形头像显示自定义View
- 【Android自定义View实战】之自定义圆形头像CircleImageView支持加载网络图片
- Android自定义控件之圆形头像
- android分析之自定义圆形头像
- Android自定义控件之圆形头像
- Android自定义控件之圆形头像
- Android自定义圆形头像
- android自定义圆形头像
- 网络编程中出现connection refused错误
- 简易QQ通讯录
- SDP(Session Description Protocol)模型介绍(RFC3264)
- 济南中青旅这是爱上桂林了的节奏
- button文字左对齐
- Android自定义View之圆形头像
- Hisi3518应用拾遗
- 用Split按字符、多字符、字符串把字符串分割成数组
- 数据库创建连续日期表
- 常见邮件服务器(接收服务器和发送邮件服务器)地址
- ASI 缓存设置
- ubuntu操作遇到问题
- x264源代码简单分析:编码器主干部分-2
- 关于摄像头的一些基础知识