1.1 双指旋转
1.2 单指拖拽
1.3 双指推压、双指拉取
1.4 双指缩放
2.准备工作
也可直接参考项目代码
文章示例代码
2.1 step1:在项目级build.gradle中添加jitpack仓库
//step-1.1:添加jitpack仓库
maven { url 'https://jitpack.io' }
两个repositories闭包均添加,如:
buildscript {
repositories {
...
//step-1.1:添加jitpack仓库
maven { url 'https://jitpack.io' }
}
...
}
allprojects {
repositories {
google()
jcenter()
//step-1.2:添加jitpack仓库
maven { url 'https://jitpack.io' }
}
}
2.2 step2:moudule的build.gradle导包
//step-2:导包
implementation 'com.github.Almeros:android-gesture-detectors:v1.0.1'
2.3 step3:布局代码
res/layout/activity_rotate.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
android:src="@mipmap/ic_football"
/>
</RelativeLayout>
3.旋转手势
用法&思路:
- 声明RotateGestureDetector对象,初始化,设置监听器等;
- 获取操作对象如ImageView对象,设置setOnTouchListener;
- 在OnTouchListener的onTouch回调中,RotateGestureDetector实例对象接手触摸事件;
- 旋转回调中,设置变化后的参数值;
- ontouch()回调中处理变化结果,并设置给操作对象如ImageView
代码及要点说明:
package com.cupster.easydetector;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import com.almeros.android.multitouch.MoveGestureDetector;
import com.almeros.android.multitouch.RotateGestureDetector;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class RotateActivity extends AppCompatActivity implements View.OnTouchListener {
private float mFocusX = 0.0f;
private float mFocusY = 0.0f;
private int mImageHeight, mImageWidth;
private Matrix mMatrix = new Matrix();
private float mRotationDegrees = 0.0f;//旋转角度
private float mScaleFactor = 0.5f;//初始缩放系数
private RotateGestureDetector mRotateDetector;
private MoveGestureDetector mMoveDetector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rotate);
ImageView img = (ImageView) findViewById(R.id.image);
img.setOnTouchListener(this);
mFocusX = getResources().getDisplayMetrics().widthPixels/2f;
mFocusY = getResources().getDisplayMetrics().heightPixels/2f;
mImageWidth = img.getDrawable().getIntrinsicWidth();
mImageHeight = img.getDrawable().getIntrinsicHeight();
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
//初始缩放、位置居中
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
img.setImageMatrix(mMatrix);
mRotateDetector = new RotateGestureDetector(getApplicationContext(), new RotateGestureDetector.SimpleOnRotateGestureListener(){
@Override
public boolean onRotate(RotateGestureDetector detector) {
mRotationDegrees -= detector.getRotationDegreesDelta();
return true;
}
});
mMoveDetector = new MoveGestureDetector(getApplicationContext(), new MoveGestureDetector.SimpleOnMoveGestureListener(){
@Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
return true;
}
});
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mRotateDetector.onTouchEvent(motionEvent);
mMoveDetector.onTouchEvent(motionEvent);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postRotate(mRotationDegrees, scaledImageCenterX, scaledImageCenterY);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
( (ImageView) view).setImageMatrix(mMatrix);
return true;//true:消费掉事件,不继续分发
}
}
4.拖拽手势
用法&思路:
- 声明MoveGestureDetector对象,初始化,设置监听器等;
- 获取操作对象如ImageView对象,设置setOnTouchListener;
- 在OnTouchListener的onTouch回调中,MoveGestureDetector实例对象接手触摸事件;
- 旋转回调中,设置变化后的参数值;
- ontouch()回调中处理变化结果,并设置给操作对象如ImageView
代码及要点说明:
package com.cupster.easydetector;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import com.almeros.android.multitouch.MoveGestureDetector;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class MoveActivity extends AppCompatActivity implements View.OnTouchListener {
private float mFocusX = 0.0f;
private float mFocusY = 0.0f;
private int mImageHeight, mImageWidth;
private Matrix mMatrix = new Matrix();
private MoveGestureDetector mMoveDetector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rotate);
ImageView img = (ImageView) findViewById(R.id.image);
img.setOnTouchListener(this);
mFocusX = getResources().getDisplayMetrics().widthPixels/2f;
mFocusY = getResources().getDisplayMetrics().heightPixels/2f;
mImageWidth = img.getDrawable().getIntrinsicWidth();
mImageHeight = img.getDrawable().getIntrinsicHeight();
//初始位置居中
mMatrix.postTranslate(mFocusX - mImageWidth/2f, mFocusY - mImageHeight/2f);
img.setImageMatrix(mMatrix);
mMoveDetector = new MoveGestureDetector(getApplicationContext(), new MoveGestureDetector.SimpleOnMoveGestureListener(){
@Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
return true;
}
});
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mMoveDetector.onTouchEvent(motionEvent);
mMatrix.reset();
mMatrix.postTranslate(mFocusX - mImageWidth/2f, mFocusY - mImageHeight/2f);
( (ImageView) view).setImageMatrix(mMatrix);
return true;//true:消费掉事件,不继续分发
}
}
5.双指推拉手势
用法&思路:
- 声明ShoveGestureDetector对象,初始化,设置监听器等;
- 获取操作对象如ImageView对象,设置setOnTouchListener;
- 在OnTouchListener的onTouch回调中,ShoveGestureDetector实例对象接手触摸事件;
- 旋转回调中,设置变化后的参数值;
- ontouch()回调中处理变化结果,并设置给操作对象如ImageView
代码及要点说明:
package com.cupster.easydetector;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import com.almeros.android.multitouch.MoveGestureDetector;
import com.almeros.android.multitouch.ShoveGestureDetector;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class PressPushActivity extends AppCompatActivity implements View.OnTouchListener {
private float mFocusX = 0.0f;
private float mFocusY = 0.0f;
private int mImageHeight, mImageWidth;
private int mAlpha = 255;
private Matrix mMatrix = new Matrix();
private MoveGestureDetector mMoveDetector;
private ShoveGestureDetector mShoveDetector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rotate);
ImageView img = (ImageView) findViewById(R.id.image);
img.setOnTouchListener(this);
mFocusX = getResources().getDisplayMetrics().widthPixels/2f;
mFocusY = getResources().getDisplayMetrics().heightPixels/2f;
mImageWidth = img.getDrawable().getIntrinsicWidth();
mImageHeight = img.getDrawable().getIntrinsicHeight();
//初始缩放、位置居中
mMatrix.postTranslate(mFocusX - mImageWidth/2f, mFocusY - mImageHeight/2f);
img.setImageMatrix(mMatrix);
mMoveDetector = new MoveGestureDetector(getApplicationContext(), new MoveGestureDetector.SimpleOnMoveGestureListener(){
@Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
return true;
}
});
mShoveDetector = new ShoveGestureDetector(getApplicationContext(), new ShoveGestureDetector.SimpleOnShoveGestureListener(){
@Override
public boolean onShove(ShoveGestureDetector detector) {
mAlpha += detector.getShovePixelsDelta();
if (mAlpha > 255){
mAlpha = 255;
} else if (mAlpha < 0){
mAlpha = 0;
}
return true;
}
});
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mMoveDetector.onTouchEvent(motionEvent);
mShoveDetector.onTouchEvent(motionEvent);
mMatrix.reset();
mMatrix.postTranslate(mFocusX - mImageWidth/2f, mFocusY - mImageHeight/2f);
( (ImageView) view).setImageMatrix(mMatrix);
( (ImageView) view).getDrawable().setAlpha(mAlpha);
return true;//true:消费掉事件,不继续分发
}
}
5.缩放手势
用法&思路:
- 声明ScaleGestureDetector对象,初始化,设置监听器等;
- 获取操作对象如ImageView对象,设置setOnTouchListener;
- 在OnTouchListener的onTouch回调中,ScaleGestureDetector实例对象接手触摸事件;
- 旋转回调中,设置变化后的参数值;
- ontouch()回调中处理变化结果,并设置给操作对象如ImageView
代码及要点说明:
package com.cupster.easydetector;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
import com.almeros.android.multitouch.MoveGestureDetector;
import com.almeros.android.multitouch.RotateGestureDetector;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class ScaleActivity extends AppCompatActivity implements View.OnTouchListener {
private float mFocusX = 0.0f;
private float mFocusY = 0.0f;
private int mImageHeight, mImageWidth;
private Matrix mMatrix = new Matrix();
private float mScaleFactor = 0.5f;//初始缩放系数
private float mMinScale = 0.2f;//min缩放系数
private float mMaxScale = 10.0f;//max缩放系数
private ScaleGestureDetector mScaleDetector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rotate);
ImageView img = (ImageView) findViewById(R.id.image);
img.setOnTouchListener(this);
mFocusX = getResources().getDisplayMetrics().widthPixels/2f;
mFocusY = getResources().getDisplayMetrics().heightPixels/2f;
mImageWidth = img.getDrawable().getIntrinsicWidth();
mImageHeight = img.getDrawable().getIntrinsicHeight();
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
//初始缩放、位置居中
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
img.setImageMatrix(mMatrix);
mScaleDetector = new ScaleGestureDetector(getApplicationContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener(){
@Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
mScaleFactor = Math.max(mMinScale, Math.min(mScaleFactor, mMaxScale));
return true;
}
});
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mScaleDetector.onTouchEvent(motionEvent);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
( (ImageView) view).setImageMatrix(mMatrix);
return true;//true:消费掉事件,不继续分发
}
}
6. 其他次要代码
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_rotate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:text="旋转"
android:textAllCaps="false" />
<Button
android:id="@+id/btn_pull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:layout_marginTop="10dp"
android:text="拖拽"
android:textAllCaps="false" />
<Button
android:id="@+id/btn_press_push"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:layout_marginTop="10dp"
android:text="推压"
android:textAllCaps="false" />
<Button
android:id="@+id/btn_scale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:layout_marginTop="10dp"
android:text="缩放"
android:textAllCaps="false" />
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cupster.easydetector">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".RotateActivity" android:screenOrientation="portrait"/>
<activity android:name=".MoveActivity" android:screenOrientation="portrait"/>
<activity android:name=".PressPushActivity" android:screenOrientation="portrait"/>
<activity android:name=".ScaleActivity" android:screenOrientation="portrait"/>
</application>
</manifest>