BitmapRegionDecoder加載超大圖片

1.BitmapRegionDecoder提供了一系列的newInstance方法來構造對象,支持傳入文件路徑,文件描述符,文件的inputstrem等

if (o instanceof String) {
    inputStream = new FileInputStream((String) o);
    // 根據圖片對應的BitmapRegionDecoder對象
    mBitmapRegionDecoder = BitmapRegionDecoder.newInstance((String) o, false);
} else if (o instanceof InputStream) {
    inputStream = (InputStream) o;
    mBitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
}

2.加載部分區域,手勢的滑動加載其他部分

public class BigImageView extends View {
    private Context mContext;
    private BitmapRegionDecoder mBitmapRegionDecoder;
    private Rect mRect = new Rect();
    private int mImageWidth = 0;
    private int mImageHeight = 0;
    private BitmapFactory.Options mOptions;

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

    public BigImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BigImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init();
    }

    private void init() {
        // 指定圖片的解碼格式爲RGB_565
        mOptions = new BitmapFactory.Options();
        mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
    }

    // 傳入需要加載的圖片的inputStream
    public void setInputStream(Object o) {
        InputStream inputStream = null;
        try {
            if (o instanceof String) {
                inputStream = new FileInputStream((String) o);
                // 根據圖片對應的BitmapRegionDecoder對象
                mBitmapRegionDecoder = BitmapRegionDecoder.newInstance((String) o, false);
            } else if (o instanceof InputStream) {
                inputStream = (InputStream) o;
                mBitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
            }
            // 獲得圖片的寬高
            BitmapFactory.Options tmpOptions = new BitmapFactory.Options();
            tmpOptions.inJustDecodeBounds = true; // 將inJuestDecodeBounds設爲true,這樣BitmapFactory只會解析圖片的原始寬/高信息,並不會真正的去加載圖片
            BitmapFactory.decodeStream(inputStream, null, tmpOptions); // 解析圖片獲得圖片的寬高
            mImageWidth = tmpOptions.outWidth; // 保存圖片的寬
            mImageHeight = tmpOptions.outHeight; // 保存圖片的搞

            requestLayout(); // 這裏調用requestLayout方法,請求重新佈局,觸發調用控件的onMeasure,初始化加載區域
            invalidate(); // 調用invalidate方法,請求重繪
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 保存上一次事件的發生位置
    float lastEventX = 0;
    float lastEventY = 0;
    // 保存當前事件的發生位置
    float eventX = 0;
    float eventY = 0;

    // 重載控件的onTouchEvent方法,監控控件的事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 這裏只處理了控件的Move事件,如果有更復雜需求,比如說根據手勢縮放圖片,可以將事件交由給GestureDetector處理
        if (event != null) {
            // 得到當前事件的發生位置
            eventX = event.getX();
            eventY = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE: // move事件
                    // 根據當前事件的發生位置和上一次事件的發生位置計算出用戶的滑動距離,並調整圖片的加載區域
                    move((int) (lastEventX - eventX), (int) (lastEventY - eventY));
                    break;
            }
            // 保存上一次事件的發生位置
            lastEventX = event.getX();
            lastEventY = event.getY();
        }
        return true;
    }

    // 根據滑動距離調整圖片的加載區域
    private void move(int moveX, int moveY) {
        // 只有當圖片的高大於控件的高,控件縱向顯示不下圖片時,才需要調整加載區域的上下位置
        if (mImageHeight > getHeight()) {
            mRect.top = mRect.top + moveY;
            mRect.bottom = mRect.top + getHeight();
        }
        // 只有當圖片的寬大於控件的寬,控件橫向顯示不下圖片時,才需要調整加載區域的左右位置
        if (mImageWidth > getWidth()) {
            mRect.left = mRect.left + moveX;
            mRect.right = mRect.left + getWidth();
        }

        invalidate();
    }

    // 重寫onDraw方法,繪製圖片的局部
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mBitmapRegionDecoder != null) {
            // 檢查繪製區域的寬高,以免繪製到圖片以爲的區域
            checkHeight();
            checkWidth();
            // 加載圖片的指定區域
            Bitmap bitmap = mBitmapRegionDecoder.decodeRegion(mRect, mOptions);
            // 繪製圖片的局部到控件上
            if (bitmap != null) {
                canvas.drawBitmap(bitmap, 0, 0, null);
            }
        }
    }

    /**
     * 檢查加載區域是否超出圖片範圍
     */
    private void checkWidth() {
        // 只有當圖片的寬大於控件的寬,控件橫向顯示不下圖片時,才需要調整加載區域的左右位置
        if (mImageWidth > getWidth()) {
            if (mRect.right > mImageWidth) {
                mRect.right = mImageWidth;
                mRect.left = mRect.right - getWidth();
            }

            if (mRect.left < 0) {
                mRect.left = 0;
                mRect.right = getWidth();
            }
        } else {
            mRect.left = (mImageWidth - getWidth()) / 2;
            mRect.right = mRect.left + getWidth();
        }
    }

    /**
     * 檢查加載區域是否超出圖片範圍
     */
    private void checkHeight() {
        // 只有當圖片的高大於控件的高,控件縱向顯示不下圖片時,才需要調整加載區域的上下位置
        if (mImageHeight > getHeight()) {
            if (mRect.bottom > mImageHeight) {
                mRect.bottom = mImageHeight;
                mRect.top = mRect.bottom - getHeight();
            }
            if (mRect.top < 0) {
                mRect.top = 0;
                mRect.bottom = getHeight();
            }
        } else {
            mRect.top = (mImageHeight - getHeight()) / 2;
            mRect.bottom = mRect.top + getHeight();
        }
    }

    /**
     * 重寫測量控件大小的方法,初始化圖片的加載區域
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 得到控件的寬高
        int width = getMeasuredWidth();
        int height = getHeight();

        // 初始化圖片的加載區域爲圖片的中心,可以自行根據需求調整
        mRect.left = (mImageWidth - width) / 2;
        mRect.right = mRect.left + width;
        mRect.top = (mImageHeight - height) / 2;
        mRect.bottom = mRect.top + height;
    }
}

Demo下載地址:https://download.csdn.net/download/qq_39735504/10357041

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章