黑马程序员技术交流社区

标题: Android 自定义ImageView圆图实现【附图附代码+详解】 [打印本页]

作者: yezilail    时间: 2016-8-2 11:25
标题: Android 自定义ImageView圆图实现【附图附代码+详解】
前段时间做了个在线医生的项目,老板觉得头像用圆的好看, 于是,有了我接下来这个自定义ImageView圆图实现。项目遇到了需要实现圆头像的编辑显示,Universal就已经提供了这个显示RoundedBitmapDisplayer这个类实现了圆图功能。看它的代码可以发现是实现的Drawable

[java] view plain copy
public static class RoundedDrawable extends Drawable {  
  
        protected final float cornerRadius;  
        protected final int margin;  
  
        protected final RectF mRect = new RectF(),  
                mBitmapRect;  
        protected final BitmapShader bitmapShader;  
        protected final Paint paint;  
  
        public RoundedDrawable(Bitmap bitmap, int cornerRadius, int margin) {  
            this.cornerRadius = cornerRadius;  
            this.margin = margin;  
  
            bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);  
            mBitmapRect = new RectF (margin, margin, bitmap.getWidth() - margin, bitmap.getHeight() - margin);  
              
            paint = new Paint();  
            paint.setAntiAlias(true);  
            paint.setShader(bitmapShader);  
        }  
  
        @Override  
        protected void onBoundsChange(Rect bounds) {  
            super.onBoundsChange(bounds);  
            mRect.set(margin, margin, bounds.width() - margin, bounds.height() - margin);  
              
            // Resize the original bitmap to fit the new bound  
            Matrix shaderMatrix = new Matrix();  
            shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);  
            bitmapShader.setLocalMatrix(shaderMatrix);  
              
        }  
  
        @Override  
        public void draw(Canvas canvas) {  
            canvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);  
        }  
  
        @Override  
        public int getOpacity() {  
            return PixelFormat.TRANSLUCENT;  
        }  
  
        @Override  
        public void setAlpha(int alpha) {  
            paint.setAlpha(alpha);  
        }  
  
        @Override  
        public void setColorFilter(ColorFilter cf) {  
            paint.setColorFilter(cf);  
        }  
    }  

其实总结下来,上面圆图实现步骤就是 1、通过bitmap初始化位图着色器BitmapShader类,2、计算bitmap原始图片的rect,3、计算放置图片需要的rect。4、使用Matrix类对两个rect进行压缩,然后复制给BitmapShader着色器里去。最后是画布画图。(刚开始一直以为shader是阴影的意思,原来有道一下是着色器的意思,这个翻译其实对我理解代码还是很重要的,所以不要想当然,要勤奋点,这个是优秀程序员必备要素。)

最后我要实现的是继承ImageView实现圆图
[java] view plain copy
public class URoundedImageView extends ImageView {  
  
    private Paint mBitmapPaint,mBackgroundPaint;  
      
    private BitmapShader mBitmapShader;  
      
    private RectF mBitmapRect , mRect;  
      
    private int borderWidth;  
      
    private Bitmap mBitmap;  
      
    private Matrix shaderMatrix;  
      
    public URoundedImageView(Context context, AttributeSet attrs,  
            int defStyleAttr) {  
        super(context, attrs, defStyleAttr);  
        init();  
    }  
  
    public URoundedImageView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        init();  
    }  
  
    public URoundedImageView(Context context) {  
        super(context);  
        init();  
    }  
      
    private void init(){  
        mBitmapPaint = new Paint();  
        mBitmapPaint.setAntiAlias(true);  
         
        mBackgroundPaint = new Paint();  
        mBackgroundPaint.setAntiAlias(true);  
        mBackgroundPaint.setColor(Color.WHITE);  
         
        borderWidth = 5;  
         
        mRect = new RectF();  
        shaderMatrix = new Matrix();  
    }  
      
    @Override  
    protected void onLayout(boolean changed, int left, int top, int right,  
            int bottom) {  
        // TODO Auto-generated method stub  
        super.onLayout(changed, left, top, right, bottom);  
    }  
      
    @Override  
    protected void onDraw(Canvas canvas) {  
        mBitmap = ((BitmapDrawable) getDrawable()).getBitmap();  
         
        if (getWidth() == 0 || getHeight() == 0 || mBitmap == null) {  
            return;  
        }  
        int w = getWidth();  
        int h = getHeight();  
        int radius = Math.min(w, h) / 2;  
         
        canvas.drawCircle(w / 2, h / 2, radius, mBackgroundPaint);  
         
        //传入bitmap初始化位图着色器  
        if (mBitmapShader == null) {  
            mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,  
                    Shader.TileMode.CLAMP);  
        }  
        if (mBitmapRect == null) {  
            mBitmapRect = new RectF(borderWidth, borderWidth,  
                    mBitmap.getWidth() - borderWidth, mBitmap.getHeight()  
                            - borderWidth);  
        }  
        mBitmapPaint.setShader(mBitmapShader);  
         
        mRect.set(borderWidth, borderWidth, w - borderWidth, h - borderWidth);  
         
        //对bitmap原始图进行缩放  
        shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);  
        mBitmapShader.setLocalMatrix(shaderMatrix);  
         
        canvas.drawRoundRect(mRect, radius, radius, mBitmapPaint);  
    }  
  
}  

刚开始写的不够规范,直接在ondraw方法里面new一些需要的对象,lint提醒我们Avoid object allocations during draw/layout operations (preallocate and reuse instead)这个warning。因为ondraw会不断调用,如果一直new对象的话会吃内存。所以为了避免重复new对象,根据自己的需求进行判空操作。具体根据自己需求来优化代码,有时候为了达到需求也没办法做到在ondraw方法里不出现重复new对象的现象。



(用的时候,直接在你的xml里面定义 绝对路径引用 我上传的ImageView  就可以,其他的在你的代码里和imageView、一样的操作。)

device-2016-08-02-111325.png (398.02 KB, 下载次数: 72)

device-2016-08-02-111325.png

URoundedImageView.zip

1.07 KB, 下载次数: 59


作者: yezilail    时间: 2016-8-2 11:29
今天就分享两个小知识点吧,后期会继续整理,把项目中遇到的技术和大家分享。欢迎关注 :yezilail 。欢迎打赏!~鲜花和鼓掌~~


(后续,将介绍更多炫酷小技术,有时间的话会整理项目用到的蓝牙4.0技术,谢谢大家。)




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2