• 超大图片显示,可任意缩放,移动,不用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 }
  • 相关阅读:
    nginx一键安装脚本
    nginx动静分离之后,设置默认主页
    日志备份
    cc高防主机部署
    原型和原型链
    Git&Github分支
    Git&Github基础
    传输层协议TCP&UDP
    本地库与远程库交互
    SVG
  • 原文地址:https://www.cnblogs.com/mhbs/p/9943887.html
Copyright © 2020-2023  润新知