Android 自定义图片拖动、缩放、旋转

1|0Android 图片拖动、缩放、旋转

1|1图片拖动

定义一个类,继承AppCompatImageView

public class MyImageView extends AppCompatImageView {
//实现方法
public MyImageView(Context context) {
this(context, null);
}
//实现方法
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
//实现方法
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
}

在资源管理器中添加图片

在布局中使用自定义控件

<com.jing.ScaleImageView.view.MyImageView
android:src="@drawable/fox"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!-- android:src="@drawable/fox" 为自己图片资源,存放在res/drawable目录下,fox为无后缀的文件名 -->

实现图片拖动

public class MyImageView extends AppCompatImageView {
private Matrix matrix = new Matrix();
//用于对图像进行变换(在这个例子中是平移)。
private float lastX, lastY;
//存储上一次触摸事件的位置。
public MyImageView(Context context) {
this(context, null);
}
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setScaleType(ScaleType.MATRIX);
//将通过 Matrix 进行控制图像的缩放和变换
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//确保图像被正确绘制。
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
//ACTION_DOWN: 记录触摸开始的位置。
lastX = event.getX();
lastY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
//ACTION_MOVE: 计算触摸移动的距离,
float dx = event.getX() - lastX;
float dy = event.getY() - lastY;
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
//平移图像。然后更新视图的
}
return true;
}
}

1|2图片缩放

在图片平移的基础上添加,具体代码如下

public class MyImageView extends AppCompatImageView {
private Matrix matrix = new Matrix();
//用于对图像进行变换(在这个例子中是平移/缩放)。
private ScaleGestureDetector scaleDetector;
//用于检测和处理缩放手势。
private float lastX, lastY;
//存储上一次触摸事件的位置。
private boolean allPointersUp;
// 用于跟踪是否所有触摸点都已抬起,以区分平移和缩放操作。
public MyImageView(Context context) {
this(context, null);
}
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
//初始化了 ScaleGestureDetector 以处理缩放手势
setScaleType(ScaleType.MATRIX);
//将 ScaleType 设置为 MATRIX。将通过 Matrix 进行控制图像的缩放和变换。
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//进入缩放方法
scaleDetector.onTouchEvent(event);
final int action = event.getActionMasked();
switch (action) {
//记录触摸开始的位置,并将 allPointersUp 设置为 false。
case MotionEvent.ACTION_DOWN:
lastX = event.getX();
lastY = event.getY();
allPointersUp = false;
break;
//记录第二个触摸点按下的事件,将 allPointersUp 设置为 true。
case MotionEvent.ACTION_POINTER_DOWN:
allPointersUp = true;
break;
case MotionEvent.ACTION_MOVE:
//如果是缩放就禁止移动
if (!allPointersUp) {
float dx = event.getX() - lastX;
float dy = event.getY() - lastY;
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
lastX = event.getX();
lastY = event.getY();
}
break;
}
return true;
}
//处理缩放事件
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
//提供了缩放手势的缩放因子,允许你根据用户的缩放手势调整图像的显示大小
float scaleFactorChange = detector.getScaleFactor();
// 获取ImageView的中心点作为缩放中心点
float px = getWidth() / 2.0f;
float py = getHeight() / 2.0f;
// 在ImageView的中心点进行缩放
matrix.postScale(scaleFactorChange, scaleFactorChange, px, py);
// 应用新的矩阵变换
setImageMatrix(matrix);
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
//缩放手势结束时调用,可以在此方法中执行任何必要的清理操作。
super.onScaleEnd(detector);
}
}
}

1|3图片旋转

public class MyImageView extends AppCompatImageView {
private Matrix matrix = new Matrix();
private ScaleGestureDetector scaleDetector;
private float lastX, lastY;
private boolean isDragging;
//存储初始旋转角度
private float d;
//存储当前角度
private float newRot;
public MyImageView(Context context) {
this(context, null);
}
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
setScaleType(ScaleType.MATRIX);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
scaleDetector.onTouchEvent(event);
//进入旋转方法
handleRotation(event);
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
lastX = event.getX();
lastY = event.getY();
isDragging = true;
break;
case MotionEvent.ACTION_POINTER_DOWN:
isDragging = false;
break;
case MotionEvent.ACTION_MOVE:
if (isDragging) {
float dx = event.getX() - lastX;
float dy = event.getY() - lastY;
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
lastX = event.getX();
lastY = event.getY();
}
break;
}
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactorChange = detector.getScaleFactor();
float px = getWidth() / 2.0f;
float py = getHeight() / 2.0f;
matrix.postScale(scaleFactorChange, scaleFactorChange, px, py);
setImageMatrix(matrix);
return true;
}
}
//处理旋转事件
private void handleRotation(MotionEvent event) {
//只有是俩个手指按下才会继续下去
if (event.getPointerCount() == 2) {
if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
//计算并保存初始的旋转角度
d = rotation(event);
} else if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
newRot = rotation(event);
//计算当前的旋转角度。
matrix.postRotate(newRot - d, getWidth() / 2.0f, getHeight() / 2.0f);
//计算从上一次旋转角度 d 到当前旋转角度 newRot 的增量,并将这个增量应用到 Matrix 上。
setImageMatrix(matrix);
//更新视图的 Matrix,以应用旋转变换。
d = newRot;
//更新 d 为当前的旋转角度,以便在下次移动事件中计算正确的旋转增量。
}
}
}
//旋转角度计算
private float rotation(MotionEvent event) {
double delta_x = event.getX(1) - event.getX(0);
double delta_y = event.getY(1) - event.getY(0);
return (float) Math.toDegrees(Math.atan2(delta_y, delta_x));
}
}

2|0总结

1|01. 图片拖动

  • 创建自定义的 ImageView 类,继承 AppCompatImageView
  • 使用 Matrix 对图像进行平移变换。
  • 处理 MotionEvent 中的触摸事件,计算拖动的距离,并更新图像的位置。

1|02. 图片缩放

  • 在自定义 ImageView 中,添加对 ScaleGestureDetector 的支持。
  • ScaleGestureDetector 处理缩放手势,并提供缩放因子。
  • 使用 Matrix 进行缩放变换,更新图像显示。

1|03. 图片旋转

  • 使用两个触摸点来计算旋转角度的变化。
  • 应用旋转变换到 Matrix,更新图像显示。

3|0代码地址

https://gitee.com/lxj_dear/my-image-view


__EOF__

本文作者疾风不问归途
本文链接https://www.cnblogs.com/20lxj666/p/18339053.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   疾风不问归途  阅读(431)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示