• 41.Android之图片放大缩小学习


    生活中经常会用到图片放大和缩小,今天简单学习下.

    思路:1.添加一个操作图片放大和缩小类;  2. 布局文件中引用这个自定义控件;  3. 主Activity一些修改. 代码如下:

    增加图片操作类

      1 package com.example.imagezoomdemo;
      2 
      3 import java.util.Observable;
      4 import java.util.Observer;
      5 
      6 import android.content.Context;
      7 import android.graphics.Bitmap;
      8 import android.graphics.Canvas;
      9 import android.graphics.Paint;
     10 import android.graphics.Rect;
     11 import android.util.AttributeSet;
     12 import android.util.Log;
     13 import android.view.MotionEvent;
     14 import android.view.View;
     15 
     16 public class zoomimage extends View implements Observer {
     17 
     18     /** Paint object used when drawing bitmap. */
     19     private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
     20 
     21     /** Rectangle used (and re-used) for cropping source image. */
     22     private final Rect mRectSrc = new Rect();
     23 
     24     /** Rectangle used (and re-used) for specifying drawing area on canvas. */
     25     private final Rect mRectDst = new Rect();
     26 
     27     /** Object holding aspect quotient */
     28     private final AspectQuotient mAspectQuotient = new AspectQuotient();
     29 
     30     /** The bitmap that we're zooming in, and drawing on the screen. */
     31     private Bitmap mBitmap;
     32 
     33     /** State of the zoom. */
     34     private ZoomState mState;
     35 
     36     private BasicZoomControl mZoomControl;
     37     private BasicZoomListener mZoomListener;
     38 
     39     public zoomimage(Context context, AttributeSet attrs) {
     40         super(context, attrs);
     41 
     42         mZoomControl = new BasicZoomControl();
     43 
     44         mZoomListener = new BasicZoomListener();
     45         mZoomListener.setZoomControl(mZoomControl);
     46 
     47         setZoomState(mZoomControl.getZoomState());
     48 
     49         setOnTouchListener(mZoomListener);
     50 
     51         mZoomControl.setAspectQuotient(getAspectQuotient());
     52     }
     53 
     54     public void zoomImage(float f, float x, float y) {
     55         mZoomControl.zoom(f, x, y);
     56     }
     57 
     58     public void setImage(Bitmap bitmap) {
     59         mBitmap = bitmap;
     60 
     61         mAspectQuotient.updateAspectQuotient(getWidth(), getHeight(),
     62                 mBitmap.getWidth(), mBitmap.getHeight());
     63         mAspectQuotient.notifyObservers();
     64 
     65         invalidate();
     66     }
     67 
     68     private void setZoomState(ZoomState state) {
     69         if (mState != null) {
     70             mState.deleteObserver(this);
     71         }
     72 
     73         mState = state;
     74         mState.addObserver(this);
     75 
     76         invalidate();
     77     }
     78 
     79     private AspectQuotient getAspectQuotient() {
     80         return mAspectQuotient;
     81     }
     82 
     83     @Override
     84     protected void onDraw(Canvas canvas) {
     85         if (mBitmap != null && mState != null) {
     86 
     87             Log.d("ZoomImageView", "OnDraw");
     88 
     89             final float aspectQuotient = mAspectQuotient.get();
     90 
     91             final int viewWidth = getWidth();
     92             final int viewHeight = getHeight();
     93             final int bitmapWidth = mBitmap.getWidth();
     94             final int bitmapHeight = mBitmap.getHeight();
     95 
     96             Log.d("ZoomImageView", "viewWidth = " + viewWidth);
     97             Log.d("ZoomImageView", "viewHeight = " + viewHeight);
     98             Log.d("ZoomImageView", "bitmapWidth = " + bitmapWidth);
     99             Log.d("ZoomImageView", "bitmapHeight = " + bitmapHeight);
    100 
    101             final float panX = mState.getPanX();
    102             final float panY = mState.getPanY();
    103             final float zoomX = mState.getZoomX(aspectQuotient) * viewWidth
    104                     / bitmapWidth;
    105             final float zoomY = mState.getZoomY(aspectQuotient) * viewHeight
    106                     / bitmapHeight;
    107 
    108             // Setup source and destination rectangles
    109             mRectSrc.left = (int) (panX * bitmapWidth - viewWidth / (zoomX * 2));
    110             mRectSrc.top = (int) (panY * bitmapHeight - viewHeight
    111                     / (zoomY * 2));
    112             mRectSrc.right = (int) (mRectSrc.left + viewWidth / zoomX);
    113             mRectSrc.bottom = (int) (mRectSrc.top + viewHeight / zoomY);
    114             // mRectDst.left = getLeft();
    115             mRectDst.left = 0;
    116             mRectDst.top = 0;
    117             // mRectDst.right = getRight();
    118             mRectDst.right = getWidth();
    119             mRectDst.bottom = getHeight();
    120 
    121             // Adjust source rectangle so that it fits within the source image.
    122             if (mRectSrc.left < 0) {
    123                 mRectDst.left += -mRectSrc.left * zoomX;
    124                 mRectSrc.left = 0;
    125             }
    126             if (mRectSrc.right > bitmapWidth) {
    127                 mRectDst.right -= (mRectSrc.right - bitmapWidth) * zoomX;
    128                 mRectSrc.right = bitmapWidth;
    129             }
    130             if (mRectSrc.top < 0) {
    131                 mRectDst.top += -mRectSrc.top * zoomY;
    132                 mRectSrc.top = 0;
    133             }
    134             if (mRectSrc.bottom > bitmapHeight) {
    135                 mRectDst.bottom -= (mRectSrc.bottom - bitmapHeight) * zoomY;
    136                 mRectSrc.bottom = bitmapHeight;
    137             }
    138 
    139             mRectDst.left = 0;
    140             mRectDst.top = 0;
    141             mRectDst.right = viewWidth;
    142             mRectDst.bottom = viewHeight;
    143 
    144             Log.d("ZoomImageView", "mRectSrc.top" + mRectSrc.top);
    145             Log.d("ZoomImageView", "mRectSrc.bottom" + mRectSrc.bottom);
    146             Log.d("ZoomImageView", "mRectSrc.left" + mRectSrc.left);
    147             Log.d("ZoomImageView", "mRectSrc.right" + mRectSrc.right);
    148 
    149             Log.d("ZoomImageView", "mRectDst.top" + mRectDst.top);
    150             Log.d("ZoomImageView", "mRectDst.bottom" + mRectDst.bottom);
    151             Log.d("ZoomImageView", "mRectDst.left" + mRectDst.left);
    152             Log.d("ZoomImageView", "mRectDst.right" + mRectDst.right);
    153 
    154             canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint);
    155         }
    156     }
    157 
    158     @Override
    159     protected void onLayout(boolean changed, int left, int top, int right,
    160             int bottom) {
    161         super.onLayout(changed, left, top, right, bottom);
    162 
    163         mAspectQuotient.updateAspectQuotient(right - left, bottom - top,
    164                 mBitmap.getWidth(), mBitmap.getHeight());
    165         mAspectQuotient.notifyObservers();
    166     }
    167 
    168     @Override
    169     public void update(Observable observable, Object data) {
    170         invalidate();
    171     }
    172 
    173     private class BasicZoomListener implements View.OnTouchListener {
    174 
    175         /** Zoom control to manipulate */
    176         private BasicZoomControl mZoomControl;
    177 
    178         private float mFirstX = -1;
    179         private float mFirstY = -1;
    180         private float mSecondX = -1;
    181         private float mSecondY = -1;
    182 
    183         private int mOldCounts = 0;
    184 
    185         /**
    186          * Sets the zoom control to manipulate
    187          * 
    188          * @param control
    189          *            Zoom control
    190          */
    191         public void setZoomControl(BasicZoomControl control) {
    192             mZoomControl = control;
    193         }
    194 
    195         public boolean onTouch(View v, MotionEvent event) {
    196 
    197             switch (event.getAction()) {
    198             case MotionEvent.ACTION_DOWN:
    199                 mOldCounts = 1;
    200                 mFirstX = event.getX();
    201                 mFirstY = event.getY();
    202                 break;
    203             case MotionEvent.ACTION_MOVE: {
    204                 float fFirstX = event.getX();
    205                 float fFirstY = event.getY();
    206 
    207                 int nCounts = event.getPointerCount();
    208 
    209                 if (1 == nCounts) {
    210                     mOldCounts = 1;
    211                     float dx = (fFirstX - mFirstX) / v.getWidth();
    212                     float dy = (fFirstY - mFirstY) / v.getHeight();
    213                     mZoomControl.pan(-dx, -dy);
    214                 } else if (1 == mOldCounts) {
    215                     mSecondX = event.getX(event.getPointerId(nCounts - 1));
    216                     mSecondY = event.getY(event.getPointerId(nCounts - 1));
    217                     mOldCounts = nCounts;
    218                 } else {
    219                     float fSecondX = event
    220                             .getX(event.getPointerId(nCounts - 1));
    221                     float fSecondY = event
    222                             .getY(event.getPointerId(nCounts - 1));
    223 
    224                     double nLengthOld = getLength(mFirstX, mFirstY, mSecondX,
    225                             mSecondY);
    226                     double nLengthNow = getLength(fFirstX, fFirstY, fSecondX,
    227                             fSecondY);
    228 
    229                     float d = (float) ((nLengthNow - nLengthOld) / v.getWidth());
    230 
    231                     mZoomControl.zoom((float) Math.pow(20, d),
    232                             ((fFirstX + fSecondX) / 2 / v.getWidth()),
    233                             ((fFirstY + fSecondY) / 2 / v.getHeight()));
    234 
    235                     mSecondX = fSecondX;
    236                     mSecondY = fSecondY;
    237                 }
    238                 mFirstX = fFirstX;
    239                 mFirstY = fFirstY;
    240 
    241                 break;
    242             }
    243 
    244             }
    245 
    246             return true;
    247         }
    248 
    249         private double getLength(float x1, float y1, float x2, float y2) {
    250             return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
    251         }
    252     }
    253 
    254     private class BasicZoomControl implements Observer {
    255 
    256         /** Minimum zoom level limit */
    257         private static final float MIN_ZOOM = 1;
    258 
    259         /** Maximum zoom level limit */
    260         private static final float MAX_ZOOM = 16;
    261 
    262         /** Zoom state under control */
    263         private final ZoomState mState = new ZoomState();
    264 
    265         /** Object holding aspect quotient of view and content */
    266         private AspectQuotient mAspectQuotient;
    267 
    268         /**
    269          * Set reference object holding aspect quotient
    270          * 
    271          * @param aspectQuotient
    272          *            Object holding aspect quotient
    273          */
    274         public void setAspectQuotient(AspectQuotient aspectQuotient) {
    275             if (mAspectQuotient != null) {
    276                 mAspectQuotient.deleteObserver(this);
    277             }
    278 
    279             mAspectQuotient = aspectQuotient;
    280             mAspectQuotient.addObserver(this);
    281         }
    282 
    283         /**
    284          * Get zoom state being controlled
    285          * 
    286          * @return The zoom state
    287          */
    288         public ZoomState getZoomState() {
    289             return mState;
    290         }
    291 
    292         /**
    293          * Zoom
    294          * 
    295          * @param f
    296          *            Factor of zoom to apply
    297          * @param x
    298          *            X-coordinate of invariant position
    299          * @param y
    300          *            Y-coordinate of invariant position
    301          */
    302         public void zoom(float f, float x, float y) {
    303 
    304             // Log.d("Zoom", "zoom f = " + f);
    305 
    306             final float aspectQuotient = mAspectQuotient.get();
    307 
    308             final float prevZoomX = mState.getZoomX(aspectQuotient);
    309             final float prevZoomY = mState.getZoomY(aspectQuotient);
    310 
    311             mState.setZoom(mState.getZoom() * f);
    312             limitZoom();
    313 
    314             final float newZoomX = mState.getZoomX(aspectQuotient);
    315             final float newZoomY = mState.getZoomY(aspectQuotient);
    316 
    317             // Pan to keep x and y coordinate invariant
    318             mState.setPanX(mState.getPanX() + (x - .5f)
    319                     * (1f / prevZoomX - 1f / newZoomX));
    320             mState.setPanY(mState.getPanY() + (y - .5f)
    321                     * (1f / prevZoomY - 1f / newZoomY));
    322 
    323             limitPan();
    324 
    325             mState.notifyObservers();
    326         }
    327 
    328         /**
    329          * Pan
    330          * 
    331          * @param dx
    332          *            Amount to pan in x-dimension
    333          * @param dy
    334          *            Amount to pan in y-dimension
    335          */
    336         public void pan(float dx, float dy) {
    337             final float aspectQuotient = mAspectQuotient.get();
    338 
    339             mState.setPanX(mState.getPanX() + dx
    340                     / mState.getZoomX(aspectQuotient));
    341             mState.setPanY(mState.getPanY() + dy
    342                     / mState.getZoomY(aspectQuotient));
    343 
    344             limitPan();
    345 
    346             mState.notifyObservers();
    347         }
    348 
    349         /**
    350          * Help function to figure out max delta of pan from center position.
    351          * 
    352          * @param zoom
    353          *            Zoom value
    354          * @return Max delta of pan
    355          */
    356         private float getMaxPanDelta(float zoom) {
    357             return Math.max(0f, .5f * ((zoom - 1) / zoom));
    358         }
    359 
    360         /**
    361          * Force zoom to stay within limits
    362          */
    363         private void limitZoom() {
    364             if (mState.getZoom() < MIN_ZOOM) {
    365                 mState.setZoom(MIN_ZOOM);
    366             } else if (mState.getZoom() > MAX_ZOOM) {
    367                 mState.setZoom(MAX_ZOOM);
    368             }
    369         }
    370 
    371         /**
    372          * Force pan to stay within limits
    373          */
    374         private void limitPan() {
    375             final float aspectQuotient = mAspectQuotient.get();
    376 
    377             final float zoomX = mState.getZoomX(aspectQuotient);
    378             final float zoomY = mState.getZoomY(aspectQuotient);
    379 
    380             final float panMinX = .5f - getMaxPanDelta(zoomX);
    381             final float panMaxX = .5f + getMaxPanDelta(zoomX);
    382             final float panMinY = .5f - getMaxPanDelta(zoomY);
    383             final float panMaxY = .5f + getMaxPanDelta(zoomY);
    384 
    385             if (mState.getPanX() < panMinX) {
    386                 mState.setPanX(panMinX);
    387             }
    388             if (mState.getPanX() > panMaxX) {
    389                 mState.setPanX(panMaxX);
    390             }
    391             if (mState.getPanY() < panMinY) {
    392                 mState.setPanY(panMinY);
    393             }
    394             if (mState.getPanY() > panMaxY) {
    395                 mState.setPanY(panMaxY);
    396             }
    397         }
    398 
    399         // Observable interface implementation
    400 
    401         public void update(Observable observable, Object data) {
    402             limitZoom();
    403             limitPan();
    404         }
    405     }
    406 
    407     private class AspectQuotient extends Observable {
    408 
    409         /**
    410          * Aspect quotient
    411          */
    412         private float mAspectQuotient;
    413 
    414         // Public methods
    415 
    416         /**
    417          * Gets aspect quotient
    418          * 
    419          * @return The aspect quotient
    420          */
    421         public float get() {
    422             return mAspectQuotient;
    423         }
    424 
    425         /**
    426          * Updates and recalculates aspect quotient based on supplied view and
    427          * content dimensions.
    428          * 
    429          * @param viewWidth
    430          *            Width of view
    431          * @param viewHeight
    432          *            Height of view
    433          * @param contentWidth
    434          *            Width of content
    435          * @param contentHeight
    436          *            Height of content
    437          */
    438         public void updateAspectQuotient(float viewWidth, float viewHeight,
    439                 float contentWidth, float contentHeight) {
    440             final float aspectQuotient = (contentWidth / contentHeight)
    441                     / (viewWidth / viewHeight);
    442 
    443             if (aspectQuotient != mAspectQuotient) {
    444                 mAspectQuotient = aspectQuotient;
    445                 setChanged();
    446             }
    447         }
    448     }
    449 
    450     private class ZoomState extends Observable {
    451         /**
    452          * Zoom level A value of 1.0 means the content fits the view.
    453          */
    454         private float mZoom;
    455 
    456         /**
    457          * Pan position x-coordinate X-coordinate of zoom window center
    458          * position, relative to the width of the content.
    459          */
    460         private float mPanX;
    461 
    462         /**
    463          * Pan position y-coordinate Y-coordinate of zoom window center
    464          * position, relative to the height of the content.
    465          */
    466         private float mPanY;
    467 
    468         // Public methods
    469 
    470         /**
    471          * Get current x-pan
    472          * 
    473          * @return current x-pan
    474          */
    475         public float getPanX() {
    476             return mPanX;
    477         }
    478 
    479         /**
    480          * Get current y-pan
    481          * 
    482          * @return Current y-pan
    483          */
    484         public float getPanY() {
    485             return mPanY;
    486         }
    487 
    488         /**
    489          * Get current zoom value
    490          * 
    491          * @return Current zoom value
    492          */
    493         public float getZoom() {
    494             return mZoom;
    495         }
    496 
    497         /**
    498          * Help function for calculating current zoom value in x-dimension
    499          * 
    500          * @param aspectQuotient
    501          *            (Aspect ratio content) / (Aspect ratio view)
    502          * @return Current zoom value in x-dimension
    503          */
    504         public float getZoomX(float aspectQuotient) {
    505             return Math.min(mZoom, mZoom * aspectQuotient);
    506         }
    507 
    508         /**
    509          * Help function for calculating current zoom value in y-dimension
    510          * 
    511          * @param aspectQuotient
    512          *            (Aspect ratio content) / (Aspect ratio view)
    513          * @return Current zoom value in y-dimension
    514          */
    515         public float getZoomY(float aspectQuotient) {
    516             return Math.min(mZoom, mZoom / aspectQuotient);
    517         }
    518 
    519         /**
    520          * Set pan-x
    521          * 
    522          * @param panX
    523          *            Pan-x value to set
    524          */
    525         public void setPanX(float panX) {
    526             if (panX != mPanX) {
    527                 mPanX = panX;
    528                 setChanged();
    529             }
    530         }
    531 
    532         /**
    533          * Set pan-y
    534          * 
    535          * @param panY
    536          *            Pan-y value to set
    537          */
    538         public void setPanY(float panY) {
    539             if (panY != mPanY) {
    540                 mPanY = panY;
    541                 setChanged();
    542             }
    543         }
    544 
    545         /**
    546          * Set zoom
    547          * 
    548          * @param zoom
    549          *            Zoom value to set
    550          */
    551         public void setZoom(float zoom) {
    552             if (zoom != mZoom) {
    553                 mZoom = zoom;
    554                 setChanged();
    555             }
    556         }
    557     }
    558 }

    布局修改:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="fill_parent"
     4     android:layout_height="fill_parent"
     5     android:orientation="vertical" >
     6 
     7   <!-- 引用自定义控件 -->
     8     <com.example.imagezoomdemo.zoomimage
     9         android:id="@+id/image"
    10         android:layout_width="wrap_content"
    11         android:layout_height="wrap_content" >
    12     </com.example.imagezoomdemo.zoomimage>
    13 
    14 </LinearLayout>

    最后修改下Activity:

     1 package com.example.imagezoomdemo;
     2 
     3 import android.app.Activity;
     4 import android.os.Bundle;
     5 import android.graphics.Bitmap;
     6 import android.graphics.BitmapFactory;
     7  
     8 public class MainActivity extends Activity {
     9 
    10      private zoomimage zoomImg;
    11      
    12     @Override
    13     protected void onCreate(Bundle savedInstanceState) {
    14         super.onCreate(savedInstanceState);
    15         setContentView(R.layout.activity_main);
    16         
    17          zoomImg = (zoomimage) findViewById(R.id.image);
    18             Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(),
    19                     R.drawable.aa);
    20             zoomImg.setImage(bitmap);
    21     }
    22 
    23 }

    运行效果:

    (1)原图:

    (2) 放大:

    (3) 缩小

  • 相关阅读:
    编写一个函数func(),将此函数的输入参数(int型)逆序输出显示,如54321 –> 12345,要求使用递归,并且函数体代码不超过8行
    java中两种单例模式
    springMVC配置freemarker 二(问题讨论篇)
    springMVC配置freemarker
    java中@value的环境配置
    java环境log4j日志环境的配置。
    websocket协议
    http报文和浏览器缓存机制
    详解网络连接
    编码总结
  • 原文地址:https://www.cnblogs.com/benchao/p/5258765.html
Copyright © 2020-2023  润新知