传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229
今天我们学习如何实现图片(理论上选取的图片实际尺寸应大于当前手机的屏幕尺寸)拖拉和多点触摸缩放功能。其中多点触摸缩放功能模拟器上不支持,需要在真机下测试。下面给出该场景的案例:
1案例技术要点
(1)图片变换矩阵(android.graphics.Matrix):提供记录图片位置、记录图片缩放比例、实现图片移动等。
(2)图片坐标点(android.graphics.PointF):提供记录图片起点和中心点坐标等。
(3)重写图片所在Activity的onTouch(...)方法,处理以下几个事件:
MotionEvent.ACTION_DOWN:触点(手指)按下时触发该事件
MotionEvent.ACTION_POINTER_DOWN:当屏幕上已经有触点(手指),再有触点(手指)按下时触发该事件
MotionEvent.ACTION_MOVE:触点(手指)移动时触发该事件
MotionEvent.ACTION_UP:触点(手指)离开屏幕时触发该事件
MotionEvent.ACTION_POINTER_UP:当触点(手指)离开屏幕,但屏幕上仍有其他触点(手指)时触发该事件
2案例代码陈列
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.dragscale" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <application android:icon="@drawable/avatar" android:label="@string/app_name" > <activity android:name=".DragScaleMainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
strings.xml
<resources> <string name="app_name">ImageView拖拉与多点触摸缩放</string> </resources>
main.xml
<?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/xianyun4" android:scaleType="matrix" /> </LinearLayout>
DragScaleMainActivity.java
package com.android.dragscale; import android.app.Activity; import android.graphics.Matrix; import android.graphics.PointF; import android.os.Bundle; import android.util.FloatMath; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; public class DragScaleMainActivity extends Activity { private ImageView imageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); imageView = (ImageView) findViewById(R.id.imageView); imageView.setOnTouchListener(new OnTouchListener() { // 设置开始点 private PointF startPoint = new PointF(); // 设置图片位置的变换矩阵 private Matrix matrix = new Matrix(); // 设置图片当前位置的变换矩阵 private Matrix currentMatrix = new Matrix(); // 初始化模式参数 private int mode = 0; // 无模式 private static final int NONE = 0; // 拖拉模式 private static final int DRAG = 1; // 缩放模式 private static final int ZOOM = 2; // 开启缩放效果的门槛 private static final float ZOOM_THRESHOLD = 10.0f; // 开始距离 private float startDistance; // 中心点 private PointF middlePoint; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: mode = DRAG; // 记录图片当前的移动位置 currentMatrix.set(imageView.getImageMatrix()); // 记录开始坐标 startPoint.set(event.getX(), event.getY()); break; // 当屏幕上已经有触点(手指),再有手指按下时触发该事件 case MotionEvent.ACTION_POINTER_DOWN: mode = ZOOM; startDistance = getDistance(event); if(startDistance > ZOOM_THRESHOLD) { middlePoint = getMiddlePoint(event); // 记录图片当前的缩放比例 currentMatrix.set(imageView.getImageMatrix()); } break; case MotionEvent.ACTION_MOVE: if(mode == DRAG) { // 获取X轴移动距离 float distanceX = event.getX() - startPoint.x; // 获取Y轴移动距离 float distanceY = event.getY() - startPoint.y; // 在上次移动停止位置的基础上再进行移动 matrix.set(currentMatrix); // 实现图片位置移动 matrix.postTranslate(distanceX, distanceY); } else if(mode == ZOOM) { // 结束距离 float endDistance = getDistance(event); if(endDistance > ZOOM_THRESHOLD) { // 缩放比例 float scale = endDistance / startDistance; matrix.set(currentMatrix); matrix.postScale(scale, scale, middlePoint.x, middlePoint.y); } } break; case MotionEvent.ACTION_UP: // 当手指离开屏幕,但屏幕上仍有其他触点(手指)时触发该事件 case MotionEvent.ACTION_POINTER_UP: mode = 0; break; } imageView.setImageMatrix(matrix); return true; } }); } /** * 计算两点之间的距离 * @param event * @return */ public static float getDistance(MotionEvent event) { //第二个点x、y坐标减去第一个点x、y坐标 float disX = event.getX(1) - event.getX(0); float disY = event.getY(1) - event.getY(0); return FloatMath.sqrt(disX * disX + disY * disY); } /** * 计算两点之间的中间点 * @param event * @return */ public static PointF getMiddlePoint(MotionEvent event) { float midX = (event.getX(0) + event.getX(1)) /2; float midY = (event.getY(0) + event.getY(1)) /2; return new PointF(midX, midY); } }注意:提供一张图片(壁纸)存放于drawable-hdpi文件夹下。