一个简单的自定义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>