美文网首页
面试之——Android-Universal-Image-Loa

面试之——Android-Universal-Image-Loa

作者: 的一幕 | 来源:发表于2018-01-31 18:20 被阅读29次

    通过前面两篇的学习,总算对Android-Universal-Image-Loader有些熟悉了。还没有看前面两篇的小伙伴们赶快去看看吧:Android-Universal-Image-Loader源码分析Android-Universal-Image-Loader缓存策略,咋们还是从Android-Universal-Image-Loader的demo看他的效果图:

    demo中的效果图.png image.png

    这里demo中通过builder中的displayer方法中传入了一个CircleBitmapDisplayer对象,最后设置给了DisplayImageOptions成员变量displayer。那最终该displayer用在了什么地方呢?那咱们还是顺着源码去看下ImageLoaderdisplayImage方法最后调用了这么一句:

    options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
    

    那咱们还是直接去刚才传的CircleBitmapDisplayerdisplay方法吧:

    @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));
    }
    

    上面是通过ImageAwaresetImageDrawable方法传了一个CircleDrawable对象,看名字都知道,其实CircleDrawable是一个Drawable对象,咱们此处的imageAware是一个ImageViewAware类型的对象,那咱们看看它的setImageDrawable方法是怎么完成显示的,该方法在父类ViewAware中实现的方法:

    @Override
    public boolean setImageDrawable(Drawable drawable) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            View view = viewRef.get();
            if (view != null) {
                setImageDrawableInto(drawable, view);
                return true;
            }
        } else {
            L.w(WARN_CANT_SET_DRAWABLE);
        }
        return false;
    }
    

    紧接着又调用了setImageDrawableInto方法,将传进来的drawable和当前的view作为参数:

    /**
     * Should set drawable into incoming view. Incoming view is guaranteed not null.<br />
     * This method is called on UI thread.
     */
    protected abstract void setImageDrawableInto(Drawable drawable, View view);
    

    好吧,转来转去还是要去子类看看如何设置这个drawable了,还是回到ImageViewAware去看看吧:

    @Override
    protected void setImageDrawableInto(Drawable drawable, View view) {
        //子类中的view一定是ImageView,所以直接强转了
        ((ImageView) view).setImageDrawable(drawable);
        //如果是有动画的drawable才走这里
        if (drawable instanceof AnimationDrawable) {
            ((AnimationDrawable)drawable).start();
        }
    }
    

    oh,my god!!!就这么简单的一句啊,说白了这里就是定义一个圆形,带外框的drawable了,下面着重就是看下CircleBitmapDisplayer中内部类CircleDrawable:

    public static class CircleDrawable extends Drawable {
        protected float radius;
        protected final RectF mRect = new RectF();
        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;
            //将当前的bitmap放到bitmapShader上,用于后面画笔画出来
            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);
            //设置了bitmapShader后,说明该画笔画的是bitmap对象了
            paint.setShader(bitmapShader);
            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;
        }
        @Override
        protected void onBoundsChange(Rect bounds) {
            super.onBoundsChange(bounds);
            //获取到view占据的位置
            mRect.set(0, 0, bounds.width(), bounds.height());
            radius = Math.min(bounds.width(), bounds.height()) / 2;
            //方框的半径要小点
            strokeRadius = radius - strokeWidth / 2;
            // Resize the original bitmap to fit the new bound
            Matrix shaderMatrix = new Matrix();
            //重新设置图片的matrix,让图片大小适应view的大小
            shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
            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);
            }
        }
        @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);
        }
    }
    

    上面画圆形的bitmap用到了paint的BitmapShader方式,这里也介绍下其他的方式实现,用paint的setXfermode来过滤也可以实现,用canvas的裁剪也可以实现。但是实现之前需要将bitmap适应当前view(放大或缩小)

    好了,图片转换就介绍到这里。期待最后一篇自定义Android-Universal-Image-Loader缓存图片转换

    相关文章

      网友评论

          本文标题:面试之——Android-Universal-Image-Loa

          本文链接:https://www.haomeiwen.com/subject/svzkzxtx.html