com.shizhefei.view.largeimage.UpdateImageView.java Source code

Java tutorial

Introduction

Here is the source code for com.shizhefei.view.largeimage.UpdateImageView.java

Source

/*
Copyright 2015 shizhefeiLuckyJayce
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
   http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
package com.shizhefei.view.largeimage;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;

import com.shizhefei.view.largeimage.BlockImageLoader.DrawData;
import com.shizhefei.view.largeimage.BlockImageLoader.OnImageLoadListener;
import com.shizhefei.view.largeimage.factory.BitmapDecoderFactory;

import java.util.List;

public class UpdateImageView extends UpdateView implements OnImageLoadListener, ILargeImageView {

    private BlockImageLoader.OnImageLoadListener onImageLoadListener;
    private int mDrawableWidth;
    private int mDrawableHeight;
    private int mLevel;

    public UpdateImageView(Context context) {
        this(context, null);
    }

    public UpdateImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public UpdateImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        imageBlockLoader = new BlockImageLoader(context);
        imageBlockLoader.setOnImageLoadListener(this);
    }

    private float mScale;
    private float mOffsetX;
    private float mOffsetY;

    public void setScale(float scale) {
        this.mScale = scale;
        notifyInvalidate();
    }

    @Override
    public float getScale() {
        return mScale;
    }

    @Override
    public OnImageLoadListener getOnImageLoadListener() {
        return onImageLoadListener;
    }

    public void setScale(float scale, float offsetX, float offsetY) {
        this.mScale = scale;
        this.mOffsetX = offsetX;
        this.mOffsetY = offsetY;
        notifyInvalidate();
    }

    @Override
    public int getImageWidth() {
        if (mDrawable != null) {
            return mDrawable.getIntrinsicWidth();
        }
        return imageBlockLoader.getWidth();
    }

    @Override
    public int getImageHeight() {
        if (mDrawable != null) {
            return mDrawable.getIntrinsicHeight();
        }
        return imageBlockLoader.getHeight();
    }

    @Override
    public void setSelected(boolean selected) {
        super.setSelected(selected);
        resizeFromDrawable();
    }

    private void resizeFromDrawable() {
        Drawable d = mDrawable;
        if (d != null) {
            int w = d.getIntrinsicWidth();
            if (w < 0)
                w = mDrawableWidth;
            int h = d.getIntrinsicHeight();
            if (h < 0)
                h = mDrawableHeight;
            if (w != mDrawableWidth || h != mDrawableHeight) {
                mDrawableWidth = w;
                mDrawableHeight = h;
                requestLayout();
            }
        }
    }

    private BlockImageLoader imageBlockLoader;

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mDrawable != null) {
            mDrawable.setVisible(getVisibility() == VISIBLE, false);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        imageBlockLoader.destroy();
        if (mDrawable != null) {
            mDrawable.setVisible(false, false);
        }
    }

    @Override
    public boolean hasLoad() {
        if (mDrawable != null) {
            return true;
        } else if (mFactory != null) {
            if (defaultDrawable != null) {
                return true;
            }
            return imageBlockLoader.hasLoad();
        }
        return false;
    }

    @Override
    public void setOnImageLoadListener(BlockImageLoader.OnImageLoadListener onImageLoadListener) {
        this.onImageLoadListener = onImageLoadListener;
    }

    @Override
    public void setImage(BitmapDecoderFactory factory) {
        setImage(factory, null);
    }

    @Override
    public void setImage(BitmapDecoderFactory factory, Drawable defaultDrawable) {
        mScale = 1;
        mOffsetX = 0;
        mOffsetY = 0;
        mDrawable = null;
        this.mFactory = factory;
        this.defaultDrawable = defaultDrawable;
        if (defaultDrawable != null) {
            onLoadImageSize(defaultDrawable.getIntrinsicWidth(), defaultDrawable.getIntrinsicHeight());
        }
        imageBlockLoader.load(factory);
    }

    private Drawable defaultDrawable;

    private Drawable mDrawable;
    private BitmapDecoderFactory mFactory;

    /**
     * Sets a Bitmap as the content of this ImageView.
     *
     * @param bm The bitmap to set
     */
    @Override
    public void setImage(Bitmap bm) {
        setImageDrawable(new BitmapDrawable(getResources(), bm));
    }

    @Override
    public void setImage(@DrawableRes int resId) {
        setImageDrawable(ContextCompat.getDrawable(getContext(), resId));
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        mFactory = null;
        mScale = 1;
        mOffsetX = 0;
        mOffsetY = 0;
        if (mDrawable != drawable) {
            final int oldWidth = mDrawableWidth;
            final int oldHeight = mDrawableHeight;
            updateDrawable(drawable);
            onLoadImageSize(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
            if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
                requestLayout();
            }
            invalidate();
        }
    }

    private void updateDrawable(Drawable d) {
        if (mDrawable != null) {
            mDrawable.setCallback(null);
            unscheduleDrawable(mDrawable);
        }
        mDrawable = d;
        if (d != null) {
            d.setCallback(this);
            DrawableCompat.setLayoutDirection(d, DrawableCompat.getLayoutDirection(d));
            if (d.isStateful()) {
                d.setState(getDrawableState());
            }
            d.setVisible(getVisibility() == VISIBLE, true);
            d.setLevel(mLevel);
            mDrawableWidth = d.getIntrinsicWidth();
            mDrawableHeight = d.getIntrinsicHeight();
            //            applyImageTint();
            //            applyColorMod();
            //
            //            configureBounds();
        } else {
            mDrawableWidth = mDrawableHeight = -1;
        }
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        Drawable d = mDrawable;
        if (d != null && d.isStateful()) {
            d.setState(getDrawableState());
        }
    }

    @Override
    public void drawableHotspotChanged(float x, float y) {
        super.drawableHotspotChanged(x, y);
        if (mDrawable != null) {
            DrawableCompat.setHotspot(mDrawable, x, y);
        }
    }

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(visibility);
        if (mDrawable != null) {
            mDrawable.setVisible(visibility == VISIBLE, false);
        }
    }

    @Override
    protected void onUpdateWindow(Rect visibilityRect) {
        //????
        if (mFactory != null && hasLoad()) {
            notifyInvalidate();
        }
    }

    private void notifyInvalidate() {
        ViewCompat.postInvalidateOnAnimation(this);
    }

    private Rect tempRect = new Rect();

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (getMeasuredWidth() == 0) {
            return;
        }
        if (mDrawable != null) {
            mDrawable.setBounds((int) mOffsetX, (int) mOffsetY, (int) (getMeasuredWidth() * mScale),
                    (int) (getMeasuredHeight() * mScale));
            mDrawable.draw(canvas);
        } else if (mFactory != null) {
            Rect visibilityRect = tempRect;
            getVisibilityRect(visibilityRect);
            float width = mScale * getWidth();
            int imgWidth = imageBlockLoader.getWidth();

            float imageScale = imgWidth / width;

            // ?
            Rect imageRect = new Rect();
            imageRect.left = (int) Math.ceil((visibilityRect.left - mOffsetX) * imageScale);
            imageRect.top = (int) Math.ceil((visibilityRect.top - mOffsetY) * imageScale);
            imageRect.right = (int) Math.ceil((visibilityRect.right - mOffsetX) * imageScale);
            imageRect.bottom = (int) Math.ceil((visibilityRect.bottom - mOffsetY) * imageScale);

            List<DrawData> drawData = imageBlockLoader.getDrawData(imageScale, imageRect);

            if (drawData.isEmpty()) {
                if (defaultDrawable != null) {
                    int height = (int) (1.0f * defaultDrawable.getIntrinsicHeight()
                            / defaultDrawable.getIntrinsicWidth() * getMeasuredWidth());
                    int offset = (getMeasuredHeight() - height) / 2;
                    defaultDrawable.setBounds((int) mOffsetX, (int) mOffsetY + offset,
                            (int) (getMeasuredWidth() * mScale), (int) (height * mScale));
                    defaultDrawable.draw(canvas);
                }
            } else {
                int saveCount = canvas.save();
                for (DrawData data : drawData) {
                    Rect drawRect = data.imageRect;
                    drawRect.left = (int) (Math.ceil(drawRect.left / imageScale) + mOffsetX);
                    drawRect.top = (int) (Math.ceil(drawRect.top / imageScale) + mOffsetY);
                    drawRect.right = (int) (Math.ceil(drawRect.right / imageScale) + mOffsetX);
                    drawRect.bottom = (int) (Math.ceil(drawRect.bottom / imageScale) + mOffsetY);
                    canvas.drawBitmap(data.bitmap, data.srcRect, drawRect, null);
                }
                canvas.restoreToCount(saveCount);
            }
        }
    }

    @Override
    public void onBlockImageLoadFinished() {
        notifyInvalidate();
        if (onImageLoadListener != null) {
            onImageLoadListener.onBlockImageLoadFinished();
        }
    }

    @Override
    public void onLoadImageSize(final int imageWidth, final int imageHeight) {
        mDrawableWidth = imageWidth;
        mDrawableHeight = imageHeight;
        notifyInvalidate();
        if (onImageLoadListener != null) {
            onImageLoadListener.onLoadImageSize(imageWidth, imageHeight);
        }
    }

    @Override
    public void onLoadFail(Exception e) {
        if (onImageLoadListener != null) {
            onImageLoadListener.onLoadFail(e);
        }
    }

}