Android實現ImageView圖片縮放和拖動

Android實現ImageView圖片縮放和拖動
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

今天我們來編寫一個縮放效果的ImageView ,網上有很多人都講了這些。但有許多人都直接使用了庫檔案,

那麼我們今天做的是直接上程式碼編寫一個拖動和縮放的ImageView,具體看效果圖

那麼簡單了分析一下。在手機上縮放圖片和拖動要用到什麼?手指對不對

那麼控制元件上什麼事件和手機有關。View.OnTouchListener 對不對。

ok,那麼先新建一個Class
···
public class BaseDragZoomImageView extends ImageView implements View.OnTouchListener
···

沒錯,繼承ImageView 並且新增View.OnTouchListener事件

然後我們看看建構函式


public BaseDragZoomImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
setOnTouchListener(this);
}
public BaseDragZoomImageView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
setOnTouchListener(this);
}
public BaseDragZoomImageView(Context context)
{
this(context, null);
setOnTouchListener(this);
}

對,在建構函式中,我們將setOnTouchListener 設定了。
那麼這個setOnTouchListener 具體怎麼做。我們就先分析一下onTouch 中MotionEvent。
我們都知道手指的操作有很多,那麼Andorid自然也將這種情況分了很多種case。
– MotionEvent.ACTION_DOWN 手指按下螢幕
– MotionEvent.ACTION_MOVE 手指在螢幕上移動
– MotionEvent.ACTION_UP 手指離開螢幕
– MotionEvent.ACTION_POINTER_UP 當觸點離開螢幕,但是螢幕上還有觸點(手指)
– MotionEvent.ACTION_POINTER_DOWN 當螢幕上已經有觸點(手指),再有一個觸點壓下螢幕

很顯然,這些看起來好像都能夠用得到。


public boolean onTouch(View v, MotionEvent event) {
/** 通過與運算保留最後八位 MotionEvent.ACTION_MASK = 255 */
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 手指壓下螢幕
case MotionEvent.ACTION_DOWN:
mode = MODE_DRAG;
// 記錄ImageView當前的移動位置
currentMatrix.set(getImageMatrix());
startPoint.set(event.getX(), event.getY());
break;
// 手指在螢幕上移動,改事件會被不斷觸發
case MotionEvent.ACTION_MOVE:
// 拖拉圖片
if (mode == MODE_DRAG) {
float dx = event.getX() - startPoint.x; // 得到x軸的移動距離
float dy = event.getY() - startPoint.y; // 得到x軸的移動距離
// 在沒有移動之前的位置上進行移動
matrix.set(currentMatrix);
matrix.postTranslate(dx, dy);
}
// 放大縮小圖片
else if (mode == MODE_ZOOM) {
float endDis = distance(event);// 結束距離
if (endDis > 10f) { // 兩個手指併攏在一起的時候畫素大於10
float scale = endDis / startDis;// 得到縮放倍數
matrix.set(currentMatrix);
matrix.postScale(scale, scale,midPoint.x,midPoint.y);
}
}
break;
// 手指離開螢幕
case MotionEvent.ACTION_UP:
// 當觸點離開螢幕,但是螢幕上還有觸點(手指)
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
// 當螢幕上已經有觸點(手指),再有一個觸點壓下螢幕
case MotionEvent.ACTION_POINTER_DOWN:
mode = MODE_ZOOM;
/** 計算兩個手指間的距離 */
startDis = distance(event);
/** 計算兩個手指間的中間點 */
if (startDis > 10f) { // 兩個手指併攏在一起的時候畫素大於10
midPoint = mid(event);
//記錄當前ImageView的縮放倍數
currentMatrix.set(getImageMatrix());
}
break;
}
setImageMatrix(matrix);
return true;
}

ok,收工。具體就只有這麼多。我們來看下整個class


package com.jonkming.easyui.image.dragzoom.ui;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.util.FloatMath;
/**
* 圖片縮放和拖動類
* @Title: BaseDragZoomImageView.java
* @Package com.jonkming.easyui.image.dragzoom.ui
* @author HuangMingming
* @date 2016/11/7 17:40
* @version V1.0
*/
public class BaseDragZoomImageView extends ImageView implements View.OnTouchListener{
/** 記錄是拖拉照片模式還是放大縮小照片模式 */
private int mode = 0;// 初始狀態
/** 拖拉照片模式 */
private static final int MODE_DRAG = 1;
/** 放大縮小照片模式 */
private static final int MODE_ZOOM = 2;
/** 用於記錄開始時候的座標位置 */
private PointF startPoint = new PointF();
/** 用於記錄拖拉圖片移動的座標位置 */
private Matrix matrix = new Matrix();
/** 用於記錄圖片要進行拖拉時候的座標位置 */
private Matrix currentMatrix = new Matrix();
/** 兩個手指的開始距離 */
private float startDis;
/** 兩個手指的中間點 */
private PointF midPoint;
public BaseDragZoomImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
setOnTouchListener(this);
}
public BaseDragZoomImageView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
setOnTouchListener(this);
}
public BaseDragZoomImageView(Context context)
{
this(context, null);
setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
/** 通過與運算保留最後八位 MotionEvent.ACTION_MASK = 255 */
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 手指壓下螢幕
case MotionEvent.ACTION_DOWN:
mode = MODE_DRAG;
// 記錄ImageView當前的移動位置
currentMatrix.set(getImageMatrix());
startPoint.set(event.getX(), event.getY());
break;
// 手指在螢幕上移動,改事件會被不斷觸發
case MotionEvent.ACTION_MOVE:
// 拖拉圖片
if (mode == MODE_DRAG) {
float dx = event.getX() - startPoint.x; // 得到x軸的移動距離
float dy = event.getY() - startPoint.y; // 得到x軸的移動距離
// 在沒有移動之前的位置上進行移動
matrix.set(currentMatrix);
matrix.postTranslate(dx, dy);
}
// 放大縮小圖片
else if (mode == MODE_ZOOM) {
float endDis = distance(event);// 結束距離
if (endDis > 10f) { // 兩個手指併攏在一起的時候畫素大於10
float scale = endDis / startDis;// 得到縮放倍數
matrix.set(currentMatrix);
matrix.postScale(scale, scale,midPoint.x,midPoint.y);
}
}
break;
// 手指離開螢幕
case MotionEvent.ACTION_UP:
// 當觸點離開螢幕,但是螢幕上還有觸點(手指)
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
// 當螢幕上已經有觸點(手指),再有一個觸點壓下螢幕
case MotionEvent.ACTION_POINTER_DOWN:
mode = MODE_ZOOM;
/** 計算兩個手指間的距離 */
startDis = distance(event);
/** 計算兩個手指間的中間點 */
if (startDis > 10f) { // 兩個手指併攏在一起的時候畫素大於10
midPoint = mid(event);
//記錄當前ImageView的縮放倍數
currentMatrix.set(getImageMatrix());
}
break;
}
setImageMatrix(matrix);
return true;
}
/** 計算兩個手指間的距離 */
private float distance(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
/** 使用勾股定理返回兩點之間的距離 */
return (float) Math.sqrt(dx * dx   dy * dy);
}
/** 計算兩個手指間的中間點 */
private PointF mid(MotionEvent event) {
float midX = (event.getX(1)   event.getX(0)) / 2;
float midY = (event.getY(1)   event.getY(0)) / 2;
return new PointF(midX, midY);
}
}

然後看佈局檔案


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.jonkming.easyui.image.dragzoom.ui.BaseDragZoomImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/dragandzoombase"
android:scaleType="matrix"
/>
</LinearLayout>

就是這麼簡單。

程式碼所在位置: GitHub

相關文章

Android 開發 最新文章