一个简单的自定义CircleDrawable,实现圆形头像效果
LayRosario
8年前
<p>Github上有一个star5000+的 CircleImageView ,代码设计得十分简洁流畅,其实通过自定义一个Drawable也完全可以实现这个效果。(ps:其实是今天在看源码的时候,在Setting模块看到了一个类似的CircleFramedDrawable~,自己几乎没有修改就能实现圆形图片的效果)。</p> <p>因为代码十分简单,所以一些简单分析就直接写在注释里了。这里只说一下实现思路:通过为画笔设置PorterDuff.Mode,来让新建的圆形图层与原Bitmap只显示重合部分。(PorterDuff.Mode:一个强大的图像转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。哈哈,说人话就是用来控制图层与图层之间如何覆盖,覆盖之后取哪部分显示到画布上,有兴趣的可以自行百度,这里只用到了两种模式。)</p> <p>下面直接上代码和效果图:</p> <p>在构造方法里处理图层关系:</p> <pre> <code class="language-java">public CircleFramedDrawable(Bitmap icon, int size) { super(); mSize = size; mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(mBitmap); final int width = icon.getWidth(); final int height = icon.getHeight(); final int square = Math.min(width, height); final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square); final RectF circleRect = new RectF(0f, 0f, mSize, mSize); final Path fillPath = new Path(); //path.addArc方法用于绘制圆弧,这个圆弧取自RectF矩形的内接椭圆上的一部分,圆弧长度由后两个角度参数决定 fillPath.addArc(circleRect, 0f, 360f); //PorterDuff.Mode.CLEAR:清除画布(所绘制不会提交到画布上) canvas.drawColor(0, PorterDuff.Mode.CLEAR); // opaque circle matte mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); mPaint.setStyle(Paint.Style.FILL); canvas.drawPath(fillPath, mPaint); // mask in the icon where the bitmap is opaque(不透明) //PorterDuff.Mode.SRC_IN:两者相交的地方绘制源图 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(icon, cropRect, circleRect, mPaint); // prepare paint for frame drawing // 别忘记还原画笔~ mPaint.setXfermode(null); mScale = 1f; mSrcRect = new Rect(0, 0, mSize, mSize); mDstRect = new RectF(0, 0, mSize, mSize); }</code></pre> <p>当然支持图片的缩放啦:</p> <pre> <code class="language-java">@Override public void draw(Canvas canvas) { //缩放处理 final float inside = mScale * mSize; final float pad = (mSize - inside) / 2f; //将矩形的坐标设置为缩放后指定的值 mDstRect.set(pad, pad, mSize - pad, mSize - pad); //第一个mSrcRect代表要绘制的bitmap区域,第二个mDstRect代表的是要将bitmap绘制在屏幕的什么地方 canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null); }</code></pre> <p>获取drawable时传入我们想要的大小就可以了</p> <pre> <code class="language-java">public static CircleFramedDrawable getInstance(Context context, Bitmap icon,float size) { Resources res = context.getResources(); float iconSize = px2dip(context,size); CircleFramedDrawable instance = new CircleFramedDrawable(icon, (int) iconSize); return instance; }</code></pre> <p>怎么使用?</p> <pre> <code class="language-java">@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.workingdog); mIcon.setImageDrawable(CircleFramedDrawable.getInstance(this,bitmap,800)); }</code></pre> <p>所以可以不用修改项目中的布局文件,直接加一个Drawable类就能在任何时候转换图片至圆形了!</p> <p>效果图:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/19cc4e1c44beb8439096d11f7b705c0c.jpg"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/6d686f454260ef1101e8646ac8d02290.jpg"></p> <p> </p> <p> </p> <p>来自:http://www.jianshu.com/p/8d9757e216ca</p> <p> </p>