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 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/20lxj666/p/18339053.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)