超大图片显示,可任意缩放,移动,不用DiskLruCache

1.演示,代码

  下载示例apk      下载项目 :  https://gitee.com/xi/LImage.git

   

2.遇到的问题

  • 想省内存,不太可能
  • 只支持拖拽手势,不支持缩放相对简单,解码view对应的区域就可以。
  • 不支持缩放好像说不过去,同时支持缩放+拖拽后变复杂,如转屏后的位置,指定锚点缩放,缩放后又移动,移动后又缩放。
  • 用系统图库打开图片?直接打开超大图片不能正常显示.用图库打开图片所在目录?没有找到相关代码.

3.缩放,移动的思路

3.1 缩放思路

  • 用一张解码区域是整张图片,但是inSampleSize大小适中的缩略图缩放.虽然图片是不清晰的,但是省内存,省解码时间.
  • 缩小过程不需要高清的.
  • 放大到100%的时候就重新解码当前view对应区域的位图,inSampleSize = 1 .

3.2 移动思路

  • 当缩放比例小于100%时,就移动缩略图,
  • 当缩放比例等于100%时,按当前view区域大小平移,重新解码对应的位图.

4.核心代码

4.1 解码

  • BitmapRegionDecoder 可以指定一个区域(大图范围内,超出会抛异常)对一张大位图解码,解出一张小位图.然后在view上显示这个小位图.
  • BitmapFactory.Options 解码选项,下面是常用的几个重要选项:
inSampleSize 缩略大小,值为2的n次幂(n为自然数).其它值无意义

inPreferredConfig

色彩模式,决定一个像素占用的字节数

inBitmap

指定复用的位图..不用在申请内存. 
  • 代码
 1     private BitmapRegionDecoder     mDecoder;
 2     private BitmapFactory.Options   mOptions;
 3     private Rect                    mDecodeRegion;
 4     void initRegionDecoder(){
 5         try {
 6             InputStream fs = getResources().getAssets().open("world_map.jpg");
 7             mDecoder = BitmapRegionDecoder.newInstance(fs,false);
 8             mBitmapWidth = mDecoder.getWidth();
 9             mBitmapHeight = mDecoder.getHeight();
10 
11             mOptions = new BitmapFactory.Options();
12             mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
13             mOptions.inSampleSize = 1;
14 
15         } catch (IOException e) {
16 
17             e.printStackTrace();
18         }
19 
20     }
21 
22 
23    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
24 
25        //...
26 
27         mDecodeRegion = new Rect(left,top,left + viewWidth ,top + viewHeight );
28 //        mDecodeRegion = new Rect(0,0,mBitmapWidth ,mBitmapHeight);
29 
30         mOptions.inSampleSize = calculateInSampleSize(mDecodeRegion.width(),mDecodeRegion.height(),viewWidth,viewHeight);
31 //        mOptions.inSampleSize = 2;
32 
33         long begin,end;
34         begin = SystemClock.elapsedRealtime();
35         mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
36         end = SystemClock.elapsedRealtime();
37 
38         //..
39     }

4.2 手势

  • ScaleGestureDetector   缩放手势识别器
  • GestureDetectorCompat  移动手势识别器 

  这两个比较简单,先构造,然后在 public boolean onTouchEvent(MotionEvent event) 里接收触摸事件,最后在相应的手势回调方法处理手势就可以.

4.3 变形

  缩放: 用变形矩阵.小于100%时移动也用变形矩阵,等于100%时自己计算.

 1     @Override
 2     protected void onDraw(Canvas canvas) {
 3 
 4         if (mPercentage < 100.0f && mThumbnailBitmap != null){
 5             canvas.drawBitmap(mThumbnailBitmap,mMatrix,mPaint);
 6         }else if(mPercentage == 100.0f && mBitmap != null){
 7             canvas.drawBitmap(mBitmap,mBitmapLeft,mBitmapTop,mPaint);
 8         }
 9         //...
10 
11     }

 4.4 LargeImageView.java

  1 package com.example.ff.limage;
  2 
  3 import android.annotation.SuppressLint;
  4 import android.content.Context;
  5 import android.content.pm.PackageInfo;
  6 import android.content.pm.PackageManager;
  7 import android.content.res.TypedArray;
  8 import android.graphics.Bitmap;
  9 import android.graphics.BitmapFactory;
 10 import android.graphics.BitmapRegionDecoder;
 11 import android.graphics.BlurMaskFilter;
 12 import android.graphics.Canvas;
 13 import android.graphics.Color;
 14 import android.graphics.Matrix;
 15 import android.graphics.Paint;
 16 import android.graphics.Point;
 17 import android.graphics.Rect;
 18 import android.os.AsyncTask;
 19 import android.os.Environment;
 20 import android.os.Parcelable;
 21 import android.os.SystemClock;
 22 import android.support.annotation.Nullable;
 23 import android.support.v4.view.GestureDetectorCompat;
 24 import android.util.AttributeSet;
 25 import android.util.Log;
 26 import android.view.GestureDetector;
 27 import android.view.MotionEvent;
 28 import android.view.ScaleGestureDetector;
 29 import android.view.View;
 30 
 31 import java.io.File;
 32 import java.io.IOException;
 33 import java.io.InputStream;
 34 import java.io.OutputStream;
 35 import java.math.BigDecimal;
 36 
 37 import static android.os.Environment.isExternalStorageRemovable;
 38 
 39 public class LargeImageView extends View {
 40 
 41     private String                  TAG = "LargeImageView";
 42 
 43     private Paint                   mPaint;
 44     private BitmapRegionDecoder     mDecoder;
 45     private BitmapFactory.Options   mOptions;
 46     private Rect                    mDecodeRegion;
 47     private static Bitmap           mThumbnailBitmap;
 48     private Bitmap                  mBitmap;
 49     private Matrix                  mMatrix;
 50     private float                   thumbnailWidth,thumbnailHeight;
 51     private float                   mPercentage;
 52     private float                   mThumbnailLeft,mThumbnailTop,mBitmapLeft,mBitmapTop;
 53     private int                     mBitmapWidth,mBitmapHeight;
 54     private Point                   mFocus;
 55     private boolean                 mScaling = false;
 56 
 57 
 58     private DiskLruCache            mDiskLruCache;
 59 
 60 
 61     public void destroyBitmaps(){
 62         Log.e(TAG, "destroyBitmaps: release bitmaps" );
 63         if (!mDecoder.isRecycled()) {
 64             mDecoder.recycle();
 65         }
 66         if (!mBitmap.isRecycled()){
 67             mBitmap.recycle();
 68             mBitmap = null;
 69         }
 70     }
 71     public void destroyThumbnailBitmap(){
 72         if (!mThumbnailBitmap.isRecycled()){
 73             mThumbnailBitmap.recycle();
 74             mThumbnailBitmap = null;
 75         }
 76     }
 77     public void createThumbnailBitmap(){
 78         if (null == mThumbnailBitmap){
 79             DecodeTask  task = new DecodeTask();
 80             task.execute(mDecodeRegion);
 81         }
 82     }
 83     public void createBitmaps(){
 84 
 85     }
 86     private class DecodeTask extends AsyncTask<Rect,Void,Void>{
 87 
 88         @Override
 89         protected Void doInBackground(Rect... rects) {
 90             Log.e(TAG, "doInBackground: "  );
 91             long begin,end;
 92 
 93             mDecodeRegion = new Rect(0,0,mBitmapWidth,mBitmapHeight);
 94 
 95             mOptions.inSampleSize = 2;
 96 
 97             begin = SystemClock.elapsedRealtime();
 98             mThumbnailBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
 99             end = SystemClock.elapsedRealtime();
100             Log.e(TAG, "doInBackground: decode mThumbnailBitmap need " + (end - begin) + "  ms. "  );
101 
102             return null;
103         }
104     }
105 
106     @Override
107     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
108         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
109     }
110 
111     // 打印Matrix内数据
112     void showMatrix(Matrix matrix,String tag){
113         // 下面的代码是为了查看matrix中的元素
114         float[] matrixValues = new float[9];
115         matrix.getValues(matrixValues);
116         String temp ;
117         for (int i = 0; i < 3; ++i) {
118             temp = "";
119             for (int j = 0; j < 3; ++j) {
120                 temp += matrixValues[3 * i + j] + "	";
121             }
122             Log.e(tag, temp);
123         }
124     }
125     private void printThumbnailRect(){
126         float left = mThumbnailLeft;
127         float top = mThumbnailTop;
128         float right = mThumbnailLeft + thumbnailWidth;
129         float bottom = mThumbnailTop + thumbnailHeight;
130 
131         Log.e(TAG, "printThumbnailRect: left = " + left + " top = " + top + " right = " + right + " bottom = " + bottom
132             + " width = " + thumbnailWidth + " height = " + thumbnailHeight);
133     }
134     private ScaleGestureDetector scaleDetector;
135     private ScaleGestureDetector.SimpleOnScaleGestureListener scaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
136         @Override
137         public boolean onScale(ScaleGestureDetector detector) {
138             float factor = detector.getScaleFactor();
139             if (factor == 1 ) return true;
140             if (mPercentage == 100 && factor > 1){
141                 return true;
142             }
143             if (thumbnailWidth * factor < mBitmapWidth){
144                 if (thumbnailWidth * factor >= mBitmapWidth * 0.01f){
145                     thumbnailWidth *= factor;
146                     thumbnailHeight *= factor;
147                     mMatrix.postScale(factor,factor,detector.getFocusX(),detector.getFocusY());
148                 }
149             }else{
150                 factor = mBitmapWidth / thumbnailWidth;
151                 mMatrix.postScale(factor,factor,detector.getFocusX(),detector.getFocusY());
152 
153                 thumbnailWidth = mBitmapWidth;
154                 thumbnailHeight = mBitmapHeight;
155                 mPercentage = 100.0f;
156 
157                 float matrix[] = new float[9];
158                 mMatrix.getValues(matrix);
159                 mThumbnailLeft = matrix[2];
160                 mThumbnailTop = matrix[5];
161 
162                 float left = mThumbnailLeft;
163                 float top = mThumbnailTop;
164                 float right = mThumbnailLeft + thumbnailWidth;
165                 float bottom = mThumbnailTop + thumbnailHeight;
166 
167                 int viewWith = getWidth();
168                 int viewHeight = getHeight();
169 
170                 mBitmapLeft = 0;
171                 mBitmapTop = 0;
172 
173                 if (left > 0){
174                     mBitmapLeft = left;
175                     mDecodeRegion.left = 0;
176                     mDecodeRegion.right = (int) (viewWith - left);
177                     if (top > 0){
178                         mBitmapTop = top;
179                         mDecodeRegion.top = 0;
180                         mDecodeRegion.bottom = (int) (viewHeight - top);
181                     }else if(bottom < viewHeight){
182                         mDecodeRegion.bottom = mBitmapHeight;
183                         mDecodeRegion.top = (int) (mBitmapHeight - bottom);
184                     }else {
185                         mDecodeRegion.top = (int) -top;
186                         mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
187                     }
188                 }else if(top > 0){
189                     mBitmapTop = top;
190                     mDecodeRegion.top = 0;
191                     mDecodeRegion.bottom = (int) (viewHeight - top);
192                     if (right < viewWith){
193                         mDecodeRegion.right = mBitmapWidth;
194                         mDecodeRegion.left = (int) (mBitmapWidth - right);
195                     }else{
196                         mDecodeRegion.left = (int) -left;
197                         mDecodeRegion.right = mDecodeRegion.left + viewWith;
198                     }
199                 }else if(right < viewWith ){
200                     mDecodeRegion.right = mBitmapWidth;
201                     mDecodeRegion.left = (int) (mBitmapWidth - right);
202                     if(bottom < viewHeight){
203                         mDecodeRegion.bottom = mBitmapHeight;
204                         mDecodeRegion.top = (int) (mBitmapHeight - bottom);
205                     }else{
206                         mDecodeRegion.top = (int) -top;
207                         mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
208                     }
209                 }else if(bottom < viewHeight){
210                     mDecodeRegion.left = (int) -left;
211                     mDecodeRegion.right = mDecodeRegion.left + viewWith;
212 
213                     mDecodeRegion.bottom = mBitmapHeight;
214                     mDecodeRegion.top = (int) (mBitmapHeight - bottom);
215                 }else{
216                     mDecodeRegion.left = (int) -left;
217                     mDecodeRegion.right = mDecodeRegion.left + viewWith;
218                     mDecodeRegion.top = (int) -top;
219                     mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
220                 }
221                 mOptions.inSampleSize = 1;
222 
223                 if (mDecodeRegion.width() > 0 && mDecodeRegion.height() > 0){
224                     mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
225                 }else{
226                     if (mBitmap != null && !mBitmap.isRecycled()){
227                         mBitmap.recycle();
228                         mBitmap = null;
229                     }
230                 }
231 
232             }
233             BigDecimal bd = new BigDecimal(thumbnailWidth * 1.0f / mBitmapWidth * 100).setScale(1,BigDecimal.ROUND_HALF_UP);
234             mPercentage = bd.floatValue();
235             Log.i(TAG, "onScale: bitmap.w = " + mThumbnailBitmap.getWidth() + " bitmap.h = " + mThumbnailBitmap.getHeight()
236                     + " thumbnailWidth = " + thumbnailWidth + " thumbnailHeight = " + thumbnailHeight);
237 
238             invalidate();
239             return true;
240         }
241 
242         @Override
243         public boolean onScaleBegin(ScaleGestureDetector detector) {
244 
245             mScaling = true;
246 
247             float focusX = detector.getFocusX();
248             float focusY = detector.getFocusY();
249             mFocus = new Point((int)focusX,(int)focusY);
250 
251             return true;
252         }
253 
254         @Override
255         public void onScaleEnd(ScaleGestureDetector detector) {
256             mScaling = false;
257             mFocus = null;
258 
259             super.onScaleEnd(detector);
260         }
261     };
262 
263     private GestureDetectorCompat scrollDetector;
264     private GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener() {
265         @Override
266         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
267 
268             if (mScaling || Math.abs(distanceX) < 5 && Math.abs(distanceY) < 5) return true;
269 
270             float matrix[] = new float[9];
271             mMatrix.getValues(matrix);
272             mThumbnailLeft = matrix[2];
273             mThumbnailTop = matrix[5];
274             int viewWith = getWidth();
275             int viewHeight = getHeight();
276 
277             if (mThumbnailLeft <= viewWith && mThumbnailLeft >= -thumbnailWidth
278                     && mThumbnailTop <= viewHeight && mThumbnailTop >= -thumbnailHeight){
279                 if (mThumbnailLeft > 0 && viewWith - mThumbnailLeft < -distanceX){
280                     distanceX = -(viewWith - mThumbnailLeft);
281                 }else if(mThumbnailLeft < 0 && mThumbnailLeft + thumbnailWidth < distanceX){
282                     distanceX = mThumbnailLeft + thumbnailWidth;
283                 }
284                 if (mThumbnailTop > 0 && viewHeight - mThumbnailTop < -distanceY){
285                     distanceY = -(viewHeight - mThumbnailTop);
286                 }else if(mThumbnailTop < 0 && mThumbnailTop + thumbnailHeight < distanceY){
287                     distanceY = mThumbnailTop + thumbnailHeight;
288                 }
289 
290                 mMatrix.postTranslate(-distanceX,-distanceY);
291 
292 
293                 if (mPercentage == 100.0f){
294                     mMatrix.getValues(matrix);
295                     mThumbnailLeft = matrix[2];
296                     mThumbnailTop = matrix[5];
297 
298                     float left = mThumbnailLeft;
299                     float top = mThumbnailTop;
300                     float right = mThumbnailLeft + thumbnailWidth;
301                     float bottom = mThumbnailTop + thumbnailHeight;
302 
303                     mBitmapLeft = 0;
304                     mBitmapTop = 0;
305 
306                     if (left > 0){
307                         mBitmapLeft = left;
308                         mDecodeRegion.left = 0;
309                         mDecodeRegion.right = (int) (viewWith - left);
310                         if (top > 0){
311                             mBitmapTop = top;
312                             mDecodeRegion.top = 0;
313                             mDecodeRegion.bottom = (int) (viewHeight - top);
314                         }else if(bottom < viewHeight){
315                             mDecodeRegion.bottom = mBitmapHeight;
316                             mDecodeRegion.top = (int) (mBitmapHeight - bottom);
317                         }else {
318                             mDecodeRegion.top = (int) -top;
319                             mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
320                         }
321                     }else if(top > 0){
322                         mBitmapTop = top;
323                         mDecodeRegion.top = 0;
324                         mDecodeRegion.bottom = (int) (viewHeight - top);
325                         if (right < viewWith){
326                             mDecodeRegion.right = mBitmapWidth;
327                             mDecodeRegion.left = (int) (mBitmapWidth - right);
328                         }else{
329                             mDecodeRegion.left = (int) -left;
330                             mDecodeRegion.right = mDecodeRegion.left + viewWith;
331                         }
332                     }else if(right < viewWith ){
333                         mDecodeRegion.right = mBitmapWidth;
334                         mDecodeRegion.left = (int) (mBitmapWidth - right);
335                         if(bottom < viewHeight){
336                             mDecodeRegion.bottom = mBitmapHeight;
337                             mDecodeRegion.top = (int) (mBitmapHeight - bottom);
338                         }else{
339                             mDecodeRegion.top = (int) -top;
340                             mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
341                         }
342                     }else if(bottom < viewHeight){
343                         mDecodeRegion.left = (int) -left;
344                         mDecodeRegion.right = mDecodeRegion.left + viewWith;
345 
346                         mDecodeRegion.bottom = mBitmapHeight;
347                         mDecodeRegion.top = (int) (mBitmapHeight - bottom);
348                     }else{
349                         mDecodeRegion.left = (int) -left;
350                         mDecodeRegion.right = mDecodeRegion.left + viewWith;
351                         mDecodeRegion.top = (int) -top;
352                         mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
353                     }
354                     mOptions.inSampleSize = 1;
355 
356                     Log.e(TAG, "onScroll: mDecodeRegion = " + mDecodeRegion );
357                     if (mDecodeRegion.width() > 0 && mDecodeRegion.height() > 0){
358                         mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
359                     }else{
360                         mBitmap = null;
361                     }
362                 }
363                 invalidate();
364             }
365             return true;
366         }
367 
368         @Override
369         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
370             return true;
371         }
372     };
373     private void initGestureDetector() {
374         scrollDetector = new GestureDetectorCompat(getContext(), simpleOnGestureListener);
375         scaleDetector = new ScaleGestureDetector(getContext(), scaleGestureListener);
376     }
377 
378     @Override
379     public boolean onTouchEvent(MotionEvent event) {
380         boolean ret = scaleDetector.onTouchEvent(event);
381         ret |= scrollDetector.onTouchEvent(event);
382         return ret || true;
383     }
384     private static final int DISK_CACHE_SIZE = 1024 * 1024 * 256; // 256MB
385     private static final String DISK_CACHE_SUBDIR = "thumbnails";
386 
387     void initCache(){
388 
389         try {
390             Context context = getContext();
391             File cacheDir = context.getCacheDir();
392 
393             cacheDir = context.getExternalCacheDir();
394 
395             final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||!isExternalStorageRemovable()
396                     ? context.getExternalCacheDir().getPath()
397                     : context.getCacheDir().getPath();
398             cacheDir = new File(cachePath + File.separator + DISK_CACHE_SUBDIR);
399 
400             PackageManager pm = context.getPackageManager();
401             PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
402 
403             int appVersion = pi.versionCode;
404             int valueCount = 1;
405 
406             mDiskLruCache = DiskLruCache.open(cacheDir, appVersion,valueCount,DISK_CACHE_SIZE);
407 
408         } catch (IOException e) {
409             e.printStackTrace();
410         } catch (PackageManager.NameNotFoundException e) {
411             e.printStackTrace();
412         }
413 
414     }
415     void init(){
416         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
417         mPaint.setStyle(Paint.Style.FILL);
418         mPaint.setTextSize(24);
419         setLayerType(View.LAYER_TYPE_SOFTWARE,mPaint);
420 
421 //        LinearGradient backGradient = new LinearGradient(0, 0, 0, mPaint.getTextSize(), new int[]{Color.BLACK, Color.GRAY ,Color.YELLOW}, null, Shader.TileMode.CLAMP);
422 //        mPaint.setShader(backGradient);
423 
424         mMatrix = new Matrix();
425 
426 //        initCache();
427 
428         initGestureDetector();
429 
430         initRegionDecoder();
431 
432     }
433     void initRegionDecoder(){
434         try {
435             InputStream fs = getResources().getAssets().open("world_map.jpg");
436             mDecoder = BitmapRegionDecoder.newInstance(fs,false);
437             mBitmapWidth = mDecoder.getWidth();
438             mBitmapHeight = mDecoder.getHeight();
439 
440             mOptions = new BitmapFactory.Options();
441             mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
442             mOptions.inSampleSize = 1;
443 
444         } catch (IOException e) {
445 
446             e.printStackTrace();
447         }
448 
449     }
450     private void getAttrs(Context context, AttributeSet attrs) {
451         TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LargeImageViewAttrs);
452         String file = ta.getString(R.styleable.LargeImageViewAttrs_src);
453         ta.recycle();
454     }
455 
456 
457     public LargeImageView(Context context) {
458         super(context);
459         init();
460     }
461 
462     public LargeImageView(Context context, @Nullable AttributeSet attrs) {
463         super(context, attrs);
464         getAttrs(context,attrs);
465         init();
466     }
467 
468     public LargeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
469         super(context, attrs, defStyleAttr);
470         getAttrs(context,attrs);
471         init();
472     }
473 
474     @SuppressLint("NewApi")
475     public LargeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
476         super(context, attrs, defStyleAttr, defStyleRes);
477         getAttrs(context,attrs);
478         init();
479     }
480 
481     @Override
482     protected void onRestoreInstanceState(Parcelable state) {
483         super.onRestoreInstanceState(state);
484     }
485 
486     @Override
487     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
488         super.onSizeChanged(w, h, oldw, oldh);
489     }
490 
491     public static int calculateInSampleSize(int width, int height, int reqWidth, int reqHeight) {
492         // Raw height and width of image
493         int inSampleSize = 1;
494 
495         if (height > reqHeight || width > reqWidth) {
496 
497             final int halfHeight = height / 2;
498             final int halfWidth = width / 2;
499 
500             if (halfHeight <= 0 || halfWidth <= 0) return inSampleSize;
501 
502             if (width > height) {
503                 // Calculate the largest inSampleSize value that is a power of 2 and keeps both
504                 // height and width larger than the requested height and width.
505                 while ((halfWidth / inSampleSize) >= reqWidth) {
506                     inSampleSize *= 2;
507                 }
508             } else {
509                 while ((halfHeight / inSampleSize) >= reqHeight) {
510                     inSampleSize *= 2;
511                 }
512             }
513         }
514         return inSampleSize;
515     }
516 
517     @Override
518     protected void onDraw(Canvas canvas) {
519 
520         if (mPercentage < 100.0f && mThumbnailBitmap != null){
521             canvas.drawBitmap(mThumbnailBitmap,mMatrix,mPaint);
522         }else if(mPercentage == 100.0f && mBitmap != null){
523             canvas.drawBitmap(mBitmap,mBitmapLeft,mBitmapTop,mPaint);
524         }
525         if (mFocus != null){
526             mPaint.setColor(Color.RED);
527             mPaint.setMaskFilter(new BlurMaskFilter(16, BlurMaskFilter.Blur.SOLID));
528             mPaint.setColor(Color.parseColor("#ff0000"));
529             canvas.drawCircle(mFocus.x,mFocus.y,16,mPaint);
530         }
531 
532         //draw percentage
533         String percentage = mPercentage + "%";
534 
535         float textSize = mPaint.getTextSize();
536         float percentWidth = mPaint.measureText("100.0%");
537 
538         float circleX = getWidth() - percentWidth  ;
539         float circleY = percentWidth  ;
540 
541         mPaint.setColor(Color.parseColor("#7f7A378B"));
542         mPaint.setMaskFilter(new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL));
543         canvas.drawCircle(circleX ,circleY,percentWidth * 0.66f,mPaint);
544 
545         mPaint.setColor(Color.WHITE);
546         mPaint.setMaskFilter(null);
547         percentWidth = mPaint.measureText(percentage);
548         circleY += textSize / 2;
549         circleX -= percentWidth / 2;
550         canvas.drawText(percentage,circleX ,circleY,mPaint);
551 
552     }
553     @Override
554     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
555 
556         Log.e(TAG, "onMeasure: " );
557 
558         int viewWidth = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
559 
560         if (viewWidth == 0) viewWidth = 56;
561 
562         viewWidth = resolveSizeAndState(viewWidth, widthMeasureSpec, 0);
563 
564         int viewHeight = getSuggestedMinimumHeight() + getPaddingBottom() + getPaddingTop();
565 
566         if (viewHeight == 0) viewHeight = 56;
567 
568         //计算最佳值,在其中解析了 heightMeasureSpec
569         viewHeight = resolveSizeAndState(viewHeight, heightMeasureSpec, 0);
570 
571         //将量算的结果保存到View的成员变量mMeasuredWidth 和mMeasuredHeight中。
572         setMeasuredDimension(viewWidth, viewHeight);
573 
574         // 量算完成之后,View的父控件就可以通过调用
575         // getMeasuredWidth、getMeasuredState、getMeasuredWidthAndState
576         // 这三个方法获取View的量算结果。
577 
578 
579         mBitmapLeft = 0;
580         mBitmapTop = 0;
581 
582         int left = mBitmapWidth / 2 - viewWidth / 2;
583         int top = mBitmapHeight / 2 - viewHeight / 2;
584 
585         mDecodeRegion = new Rect(left,top,left + viewWidth ,top + viewHeight );
586 //        mDecodeRegion = new Rect(0,0,mBitmapWidth ,mBitmapHeight);
587 
588         mOptions.inSampleSize = calculateInSampleSize(mDecodeRegion.width(),mDecodeRegion.height(),viewWidth,viewHeight);
589 //        mOptions.inSampleSize = 2;
590 
591         long begin,end;
592         begin = SystemClock.elapsedRealtime();
593         mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
594         end = SystemClock.elapsedRealtime();
595 
596         thumbnailWidth = mBitmapWidth;
597         thumbnailHeight = mBitmapHeight;
598 
599         BigDecimal bd = new BigDecimal(thumbnailWidth * 1.0f / mBitmapWidth * 100).setScale(1,BigDecimal.ROUND_HALF_UP);
600         mPercentage = bd.floatValue();
601 
602         Log.e(TAG, "init region = " + mDecodeRegion + " ratio = " + (float) mDecodeRegion.width() / mDecodeRegion.height()
603                 + " bitmap.w = " + mBitmap.getWidth() + " bitmap.h = " + mBitmap.getHeight() + " ratio = " + (float) mBitmap.getWidth() / mBitmap.getHeight()
604                 + " need " + (end - begin) + " ms");
605         if (mThumbnailBitmap != null){
606             Log.e(TAG, "onMeasure : mThumbnailBitmap is ok.");
607 
608             float width = mThumbnailBitmap.getWidth();
609             float height = mThumbnailBitmap.getHeight();
610             float dx = viewWidth / 2 - width / 2;
611             float dy = viewHeight / 2 - height / 2;
612             mMatrix.setTranslate(dx,dy);
613 
614             float factor = mBitmapWidth / width;
615             mMatrix.postScale(factor,factor,viewWidth/ 2,viewHeight /2);
616 
617         }
618     }
619 
620     @Override
621     protected void onFinishInflate() {
622         super.onFinishInflate();
623         Log.e(TAG, "onFinishInflate: " );
624         createThumbnailBitmap();
625     }
626 
627     @Override
628     protected void onAttachedToWindow() {
629         super.onAttachedToWindow();
630         Log.e(TAG, "onAttachedToWindow: " );
631     }
632     @Override
633     protected void onDetachedFromWindow() {
634         super.onDetachedFromWindow();
635         Log.e(TAG, "onDetachedFromWindow: " );
636 
637     }
638 
639     @Override
640     protected void onWindowVisibilityChanged(int visibility) {
641         super.onWindowVisibilityChanged(visibility);
642         Log.e(TAG, "onWindowVisibilityChanged : "  + visibility);
643 
644     }
645     @Override
646     public void onWindowFocusChanged(boolean hasWindowFocus) {
647         super.onWindowFocusChanged(hasWindowFocus);
648         Log.e(TAG, "onWindowFocusChanged:  hasWindowFocus = " + hasWindowFocus );
649     }
650 
651     Bitmap loadBitmapFromCache(String key){
652         Bitmap bitmap = null;
653         try {
654             DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
655             if (snapshot != null) {
656                 InputStream is = snapshot.getInputStream(0);
657                 bitmap = BitmapFactory.decodeStream(is);
658             }
659         } catch (IOException e) {
660             e.printStackTrace();
661         }
662         return bitmap;
663     }
664     void pushToCache(String key, Bitmap value){
665         try {
666             DiskLruCache.Editor editor = mDiskLruCache.edit(key);
667 
668             if (editor != null){
669                 OutputStream out = editor.newOutputStream(0);
670                 value.compress(Bitmap.CompressFormat.JPEG, 100, out);
671                 out.flush();
672                 editor.commit();
673                 mDiskLruCache.flush();
674             }
675 
676         } catch (IOException e) {
677             e.printStackTrace();
678         }
679     }
680 }
原文地址:https://www.cnblogs.com/mhbs/p/9943887.html