Android加载大图——BitmapRegionDecoder
2017-03-24 14:25
926 查看
一、前言
在Android开发中,加载图片是很常见的情况,我们一般选择传统的加载图片框架如universalimageloader,picasso,fresco等。最近群里有个朋友说,面试遇到一个面试官说加载巨图怎么解决,就是一个图片很大,比如清明上河图,世界地图等,一个屏幕显示不完,又不能缩小,压缩,该怎么解决。像这种情况当然是查官方文档了,其实android早就给我们解决方案——BitmapRegionDecoder,从API10就引入了。如下图:
![](http://upload-images.jianshu.io/upload_images/3287039-41ee176e3ad6ba0b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
看官方文档的说明,这个类就是用来显示指定区域的图像,当原始图像大,你只需要部分图像时,BitmapRegionDecoder特别有用。
二、使用
说了这么多,我们来看看怎么使用它吧
![](http://upload-images.jianshu.io/upload_images/3287039-92279a73b5060de9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
最主要的就是BitmapRegionDecode.newInstance(…)获取一个对象,然后通过这个对象去调用decodeRegion(…)得到bitmap,最后就可以显示在屏幕上了。考虑到用户可以触摸移动图像,我们用手势控制器GestureDetector来控制图片显示的区域。
public class LargeImageView extends View implements GestureDetector.OnGestureListener { private static final String TAG = "LargeImageView"; private BitmapRegionDecoder mDecoder; //绘制的区域 private volatile Rect mRect = new Rect(); private int mScaledTouchSlop; // 分别记录上次滑动的坐标 private int mLastX = 0; private int mLastY = 0; //图片的宽度和高度 private int mImageWidth, mImageHeight; //手势控制器 private GestureDetector mGestureDetector; private BitmapFactory.Options options; public LargeImageView(Context context) { super(context); init(context, null); } public LargeImageView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } public LargeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { //设置显示图片的参数,如果对图片质量有要求,就选择ARGB_8888模式 options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; mScaledTouchSlop = ViewConfiguration.get(getContext()) .getScaledTouchSlop(); Log.d(TAG, "sts:" + mScaledTouchSlop); //初始化手势控制器 mGestureDetector = new GestureDetector(context, this); //获取图片的宽高 InputStream is = null; try { is = context.getResources().getAssets().open("timg.jpg"); //初始化BitmapRegionDecode,并用它来显示图片 mDecoder = BitmapRegionDecoder .newInstance(is, false); BitmapFactory.Options tmpOptions = new BitmapFactory.Options(); // 设置为true则只获取图片的宽高等信息,不加载进内存 tmpOptions.inJustDecodeBounds = true; BitmapFactory.decodeStream(is, null, tmpOptions); mImageWidth = tmpOptions.outWidth; mImageHeight = tmpOptions.outHeight; } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); } } catch (Exception e) { e.printStackTrace(); } } } @Override public boolean onTouchEvent(MotionEvent event) { //把触摸事件交给手势控制器处理 return mGestureDetector.onTouchEvent(event); } @Override public boolean onDown(MotionEvent e) { mLastX = (int) e.getRawX(); mLastY = (int) e.getRawY(); return true; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float 4000 distanceY) { int x = (int) e2.getRawX(); int y = (int) e2.getRawY(); move(x, y); return true; } /** * 移动的时候更新图片显示的区域 * * @param x * @param y */ private void move(int x, int y) { int deltaX = x - mLastX; int deltaY = y - mLastY; Log.d(TAG, "move, deltaX:" + deltaX + " deltaY:" + deltaY); //如果图片宽度大于屏幕宽度 if (mImageWidth > getWidth()) { //移动rect区域 mRect.offset(-deltaX, 0); //检查是否到达图片最右端 if (mRect.right > mImageWidth) { mRect.right = mImageWidth; mRect.left = mImageWidth - getWidth(); } //检查左端 if (mRect.left < 0) { mRect.left = 0; mRect.right = getWidth(); } invalidate(); } //如果图片高度大于屏幕高度 if (mImageHeight > getHeight()) { mRect.offset(0, -deltaY); //是否到达最底部 if (mRect.bottom > mImageHeight) { mRect.bottom = mImageHeight; mRect.top = mImageHeight - getHeight(); } if (mRect.top < 0) { mRect.top = 0; mRect.bottom = getHeight(); } //重绘 invalidate(); } mLastX = x; mLastY = y; } @Override public void onLongPress(MotionEvent e) { mLastX = (int) e.getRawX(); mLastY = (int) e.getRawY(); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int x = (int) e2.getRawX(); int y = (int) e2.getRawY(); move(x, y); return true; } @Override protected void onDraw(Canvas canvas) { //显示图片 Bitmap bm = mDecoder.decodeRegion(mRect, options); canvas.drawBitmap(bm, 0, 0, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); int height = getMeasuredHeight(); int imageWidth = mImageWidth; int imageHeight = mImageHeight; //默认显示图片的中心区域,开发者可自行选择 mRect.left = imageWidth / 2 - width / 2; mRect.top = imageHeight / 2 - height / 2; mRect.right = mRect.left + width; mRect.bottom = mRect.top + height; } }
完整代码详见我的github
相关文章推荐
- Android使用BitmapRegionDecoder加载超大图片方案
- Android使用BitmapRegionDecoder加载超大图片方案
- android2.3.3新类--BitmapRegionDecoder
- Bitmap.Options和LruCache——Android高效加载大图、多图解决方案,有效避免程序OOM
- android2.3.3新类--BitmapRegionDecoder
- Android加载大图Bitmap发生OOM(Out Of Memmory Error)解决方案
- Android加载大图Bitmap发生OOM(Out Of Memmory Error)解决方案
- Android使用BitmapRegionDecoder获取指定区域的图片
- Android BitmapRegionDecoder截取图片
- 安卓巨图加载及触摸拖动浏览,仿鸿洋大神使用BitmapRegionDecoder。
- Android之Bitmap大图加载处理
- android.graphics.BitmapRegionDecoder
- Android使用BitMap压缩图片(高效加载大图)Code+详解
- Android加载大图Bitmap发生OOM(Out Of Memmory Error)解决方案
- android - BitmapRegionDecoder 翻译
- Android2.3使用BitmapRegionDecoder获取指定区域的图片
- android.graphics.BitmapRegionDecoder
- 【Android】Bitmap加载图片错误 java.lang.OutOfMemoryError: bitmap size exceeds VM budget
- 关于ANDROID示例程序(BITMAPFUN)——高效加载图片的坑爹地方
- 解决Android加载大图内存溢出