ImageLoader源码解析(四) 补充 Displayer的实现

ImageLoader源码解析(四) 补充 Displayer的实现

1 前言

一般来说,如果说到原型图片,或者边框,或者特别形状的图片处理,那么我们可能第一个想到的是 自定义ImageView去处理,在draw方法里写我们的逻辑
这篇文章说一下除了自定义ImageView的另外一种处理,那就是自定义一个Drawable,
这就是ImageLoader中提供的displayer的对于图片转换的解决方案

2 基础知识

  • Drawable
  • paint
  • BitmapShader
  • Bitmap
  • Matrix
  • 自定义View涉及到的Pain,Rect,Canvas等,如果对自定义View不了解,建议去看下自定义View,主要是绘制那块的处理,其实自定义Drawable和自定义View真的很像

3 解析

Imageloader中提供的有很多,最常用的,就是圆形,弧形的处理了,我们来看这两个是怎么写的

3.1 CircleBitmapDisplayer圆形Drawable

public class CircleBitmapDisplayer implements BitmapDisplayer {

    /**
     * 边框的颜色
     */
    protected final Integer strokeColor;
    /**
     * 边框宽度
     */
    protected final float strokeWidth;

    public CircleBitmapDisplayer() {
        this(null);
    }

    public CircleBitmapDisplayer(Integer strokeColor) {
        this(strokeColor, 0);
    }

    public CircleBitmapDisplayer(Integer strokeColor, float strokeWidth) {
        this.strokeColor = strokeColor;
        this.strokeWidth = strokeWidth;
    }

    @Override
    public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
        if (!(imageAware instanceof ImageViewAware)) {
            throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
        }
        imageAware.setImageDrawable(new CircleDrawable(bitmap, strokeColor, strokeWidth));
    }

    public static class CircleDrawable extends Drawable {

        /**
         * 弧度
         */
        protected float radius;
        /**
         * 绘制范围
         */
        protected final RectF mRect = new RectF();
        /**
         * bitmap范围
         */
        protected final RectF mBitmapRect;
        protected final BitmapShader bitmapShader;
        /**
         * 图形画笔
         */
        protected final Paint paint;
        /**
         * 边框画笔
         */
        protected final Paint strokePaint;
        /**
         * 边框宽度
         */
        protected final float strokeWidth;
        /**
         * 边框的弧度
         */
        protected float strokeRadius;

        public CircleDrawable(Bitmap bitmap, Integer strokeColor, float strokeWidth) {

            radius = Math.min(bitmap.getWidth(), bitmap.getHeight()) / 2;

            bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mBitmapRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());

            paint = new Paint();
            //设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。但是效果更好
            paint.setAntiAlias(true);
            paint.setShader(bitmapShader);
            //如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度
            paint.setFilterBitmap(true);
            //设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
            paint.setDither(true);
            //如果边框颜色设置了,那么就有边框
            if (strokeColor == null) {
                strokePaint = null;
            } else {
                strokePaint = new Paint();
                strokePaint.setStyle(Paint.Style.STROKE);
                strokePaint.setColor(strokeColor);
                strokePaint.setStrokeWidth(strokeWidth);
                strokePaint.setAntiAlias(true);
            }
            this.strokeWidth = strokeWidth;

            strokeRadius = radius - strokeWidth / 2;
        }

        /**
         * 范围发生变化时,可能如果imagview大小发生变化,这里会调用吧
         *
         * @param bounds
         */
        @Override
        protected void onBoundsChange(Rect bounds) {
            super.onBoundsChange(bounds);
            mRect.set(0, 0, bounds.width(), bounds.height());
            radius = Math.min(bounds.width(), bounds.height()) / 2;
            strokeRadius = radius - strokeWidth / 2;

            //重新设置bitmap的大小去适应新的绘制范围,这里其实就是fitxy处理
            Matrix shaderMatrix = new Matrix();
            /**
             * 设置变换规则,自动计算mBitmapRect->mRect变换的规则<br/>
             * 第三个参数,有FILL,start,end,center,还记得,ImageView的ScaleType吗,对比理解<br/>
             * Fill就是FitXY
             */
            shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
            //为bitmapshader设置变换矩阵
            bitmapShader.setLocalMatrix(shaderMatrix);
        }

        @Override
        public void draw(Canvas canvas) {
            //绘制bitmap
            canvas.drawCircle(radius, radius, radius, paint);
            if (strokePaint != null) {
                //绘制边框
                canvas.drawCircle(radius, radius, strokeRadius, strokePaint);
            }
        }
        //-------------------------下面是通过设置画笔,然后重绘,来支持View的一些设置(透明度,颜色过滤,也可以添加其他的属性支持)-------------------------------

        /**
         * 获取透明度的格式,看一下父类中的注释
         * {@link Drawable#getOpacity() }
         * <p>
         * 只有四个返回值
         * {@link android.graphics.PixelFormat}:
         * {@linkplain android.graphics.PixelFormat#UNKNOWN 未知},
         * {@linkplain android.graphics.PixelFormat#TRANSLUCENT 系统选择支持半透明的格式 bits},
         * {@linkplain android.graphics.PixelFormat#TRANSPARENT 系统选择支持透明度的格式 0-1 }, or
         * {@linkplain android.graphics.PixelFormat#OPAQUE 系统选择不透明格式(不需要alpha位)}.
         *
         * @return
         */
        @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);
        }
    }
}

注释很详细了,其实自定义Drawable,很像自定义一个View,我没有看过View的源码,现在让我怀疑View中其实操控的也是绘制一个Drawable,然后将Drawable显示到View中

3.2 RoundedBitmapDisplayer 弧形图像绘制
@Override
        public void draw(Canvas canvas) {
            //貌似唯一有变化的就是这里了吧,DrawCircle变成了Round
            canvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);
        }

4 参考

Android 自定义Drawable
http://www.cnblogs.com/a284628487/p/5204170.html

http://blog.csdn.net/lmj623565791/article/details/43752383

Matrix:
http://blog.csdn.net/flash129/article/details/8234599

5 解析源码

https://github.com/yizeliang/Android-Universal-Image-Loader

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值