如果是高清大图,那就说明不允许进行图片压缩,比如微博长图,清明上河图。
所以我们就要对图片进行局部显示,这就用到BitmapRegionDecoder属性,主要用于显示图片的某一块矩形区域。实际项目使用中,我们可以根据手势滑动,然后不断更新我们的Rect参数来实现具体的功能即可。
效果如下:
BitmapRegionDecoder类:
public final class BitmapRegionDecoder {
}
BitmapRegionDecoder构造方法:
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private BitmapRegionDecoder(long decoder) {
mNativeBitmapRegionDecoder = decoder;
mRecycled = false;
}
BitmapRegionDecoder 类被final进行修饰,因此无法被继承。构造方法被私有化,无法直接new对象。
BitmapRegionDecoder 提供了一系列newInstance,最终都是通过数据流来得到对象。很好理解,加载图片肯定要有图片文件才行。
// 创建 BitmapRegionDecoder 对象方法
static BitmapRegionDecoder newInstance(InputStream is, boolean isShareable)
static BitmapRegionDecoder newInstance(FileDescriptor fd, boolean isShareable)
static BitmapRegionDecoder newInstance(String pathName, boolean isShareable)
static BitmapRegionDecoder newInstance(byte[] data, int offset, int length, boolean isShareable)
使用decodeRegion方法解码一个矩形区域来返回bitmap,矩形区域可以根据手势拖动或者缩放来获取。
public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
BitmapFactory.Options.validate(options);
synchronized (mNativeLock) {
checkRecycled("decodeRegion called on recycled region decoder");
if (rect.right <= 0 || rect.bottom <= 0 || rect.left >= getWidth()
|| rect.top >= getHeight())
throw new IllegalArgumentException("rectangle is outside the image");
return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top, options,
BitmapFactory.Options.nativeInBitmap(options),
BitmapFactory.Options.nativeColorSpace(options));
}
}
通过onTouchEvent对滑动手势修改decodeRegion的区域,进行区域加载改变:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
dx = downX - event.getRawX();
dy = downY - event.getRawY();
updateRegion((int)dx, (int)dy);
break;
}
return true;
}
然后在onDraw方法中进行绘制bitmap:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mOptions.inBitmap = mBitmap;
Rect rect = new Rect(rectLeft, rectTop, rectRight, rectBottom);
mMatrix.setScale(1, 1);
mBitmap = mRegionDecoder.decodeRegion(rect, mOptions);
canvas.drawBitmap(mBitmap, mMatrix, null);
}
支持的图像格式 : 目前图像区域解码对象只支持 JPEG 和 PNG 两种图像格式。
这里写了一个自定义ImageView来加载区域图片,完整代码:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.widget.AppCompatImageView;
import java.io.IOException;
import java.io.InputStream;
public class RegionLoadImageView extends AppCompatImageView {
private BitmapRegionDecoder mRegionDecoder;
private BitmapFactory.Options mOptions = new BitmapFactory.Options();
private Bitmap mBitmap;
private Matrix mMatrix = new Matrix();
private InputStream inputStream;
private int rectLeft, rectTop, rectRight, rectBottom;
private int measuredWidht, measuredHeight;
private float dx, dy, downX, downY;
public RegionLoadImageView(Context context) {
super(context);
}
public RegionLoadImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public RegionLoadImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.S)
public void setImageRes(int imageRes) {
inputStream = getResources().openRawResource(imageRes);
setRegionDecoder(inputStream);
}
/**
* 设置区域解码器
*/
@RequiresApi(api = Build.VERSION_CODES.S)
public void setRegionDecoder(InputStream inputStream) {
try {
mRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measuredWidht = getMeasuredWidth();
measuredHeight = getMeasuredHeight();
updateRegion(0, 0);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
dx = downX - event.getRawX();
dy = downY - event.getRawY();
updateRegion((int)dx, (int)dy);
break;
}
return true;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mOptions.inBitmap = mBitmap;
Rect rect = new Rect(rectLeft, rectTop, rectRight, rectBottom);
mMatrix.setScale(1, 1);
mBitmap = mRegionDecoder.decodeRegion(rect, mOptions);
canvas.drawBitmap(mBitmap, mMatrix, null);
}
public void updateRegion(int x, int y) {
rectLeft = x;
rectTop = y;
rectRight = x + measuredWidht;
rectBottom = y + measuredHeight;
invalidate();
}
}
最后,给该自定义view设置加载大图资源,资源放在res/raw文件夹下:
regionLoadImageView?.setImageRes(R.raw.super_long)
使用的大图资源:
参考:
https://www.jianshu.com/p/613fac562145