首页 > 系统 > Android > 正文

基于Android 实现图片平移、缩放、旋转同时进行

2019-10-24 20:34:37
字体:
来源:转载
供稿:网友

这篇文章主要介绍了基于Android 实现图片平移、缩放、旋转同时进行的相关资料,需要的朋友可以参考下

前言

之前因为项目需求,其中使用到了图片的单击显示取消,图片平移缩放功能,昨天突然想再加上图片的旋转功能,在网上看了很多相关的例子,可是没看到能同时实现我想要的功能的。

需求:

(1)图片平移、缩放、旋转等一系列操作后,图片需要自动居中显示。

(2)图片旋转后选自动水平显示或者垂直显示

(3)图片在放大缩小的同时都能旋转

Demo实现部分效果截图

基于Android 实现图片平移、缩放、旋转同时进行

Demo主要代码

Java

 

 
  1. MainActivity.java 
  2. package com.practice.noyet.rotatezoomimageview; 
  3. import android.app.Activity; 
  4. import android.graphics.Bitmap; 
  5. import android.graphics.BitmapFactory; 
  6. import android.graphics.Matrix; 
  7. import android.graphics.PointF; 
  8. import android.graphics.RectF; 
  9. import android.os.AsyncTask; 
  10. import android.os.Bundle; 
  11. import android.util.DisplayMetrics; 
  12. import android.view.MotionEvent; 
  13. import android.view.View; 
  14. import android.widget.ImageView; 
  15. import com.ypy.eventbus.EventBus; 
  16. import java.io.File; 
  17. import java.math.BigDecimal; 
  18. /** 
  19. * package: com.practice.noyet.rotatezoomimageview 
  20. * Created by noyet on 2015/11/11. 
  21. */ 
  22. public class MainActivity extends Activity implements View.OnTouchListener { 
  23. private ImageView mImageView; 
  24. private PointF point0 = new PointF(); 
  25. private PointF pointM = new PointF(); 
  26. private final int NONE = 0; 
  27. /** 
  28. * 平移 
  29. */ 
  30. private final int DRAG = 1; 
  31. /** 
  32. * 旋转、缩放 
  33. */ 
  34. private final int ZOOM = 2; 
  35. /** 
  36. * 设定事件模式 
  37. */ 
  38. private int mode = NONE; 
  39. /** 
  40. * 图片缩放矩阵 
  41. */ 
  42. private Matrix matrix = new Matrix(); 
  43. /** 
  44. * 保存触摸前的图片缩放矩阵 
  45. */ 
  46. private Matrix savedMatrix = new Matrix(); 
  47. /** 
  48. * 保存触点移动过程中的图片缩放矩阵 
  49. */ 
  50. private Matrix matrix1 = new Matrix(); 
  51. /** 
  52. * 屏幕高度 
  53. */ 
  54. private int displayHeight; 
  55. /** 
  56. * 屏幕宽度 
  57. */ 
  58. private int displayWidth; 
  59. /** 
  60. * 最小缩放比例 
  61. */ 
  62. protected float minScale = 1f; 
  63. /** 
  64. * 最大缩放比例 
  65. */ 
  66. protected float maxScale = 3f; 
  67. /** 
  68. * 当前缩放比例 
  69. */ 
  70. protected float currentScale = 1f; 
  71. /** 
  72. * 多点触摸2个触摸点间的起始距离 
  73. */ 
  74. private float oldDist; 
  75. /** 
  76. * 多点触摸时图片的起始角度 
  77. */ 
  78. private float oldRotation = 0; 
  79. /** 
  80. * 旋转角度 
  81. */ 
  82. protected float rotation = 0; 
  83. /** 
  84. * 图片初始宽度 
  85. */ 
  86. private int imgWidth; 
  87. /** 
  88. * 图片初始高度 
  89. */ 
  90. private int imgHeight; 
  91. /** 
  92. * 设置单点触摸退出图片显示时,单点触摸的灵敏度(可针对不同手机单独设置) 
  93. */ 
  94. protected final int MOVE_MAX = 2; 
  95. /** 
  96. * 单点触摸时手指触发的‘MotionEvent.ACTION_MOVE'次数 
  97. */ 
  98. private int fingerNumMove = 0; 
  99. private Bitmap bm; 
  100. /** 
  101. * 保存matrix缩放比例 
  102. */ 
  103. private float matrixScale= 1; 
  104. /*private String imagePath;*/ 
  105. /** 
  106. * 显示被存入缓存中的网络图片 
  107. * 
  108. * @param event 观察者事件 
  109. */ 
  110. public void onEventMainThread(CustomEventBus event) { 
  111. if (event == null) { 
  112. return
  113. if (event.type == CustomEventBus.EventType.SHOW_PICTURE) { 
  114. bm = (Bitmap) event.obj; 
  115. showImage(); 
  116. @Override 
  117. protected void onCreate(Bundle savedInstanceState) { 
  118. super.onCreate(savedInstanceState); 
  119. setContentView(R.layout.activity_main); 
  120. initData(); 
  121. public void initData() { 
  122. // TODO Auto-generated method stub 
  123. bm = BitmapFactory.decodeResource(getResources(), R.drawable.alipay); 
  124. DisplayMetrics dm = getResources().getDisplayMetrics(); 
  125. displayWidth = dm.widthPixels; 
  126. displayHeight = dm.heightPixels; 
  127. mImageView = (ImageView) findViewById(R.id.image_view); 
  128. mImageView.setOnTouchListener(this); 
  129. showImage(); 
  130. //显示网络图片时使用 
  131. /*File file = MainApplication.getInstance().getImageCache() 
  132. .getDiskCache().get(图片路径); 
  133. if (!file.exists()) { 
  134. Toast.makeText(this, "图片路径错误", Toast.LENGTH_SHORT).show(); 
  135. } else { 
  136. new MyTask().execute(file); 
  137. }*/ 
  138. @Override 
  139. public boolean onTouch(View view, MotionEvent event) { 
  140. ImageView imageView = (ImageView) view; 
  141. switch (event.getAction() & MotionEvent.ACTION_MASK) { 
  142. case MotionEvent.ACTION_DOWN: 
  143. savedMatrix.set(matrix); 
  144. point0.set(event.getX(), event.getY()); 
  145. mode = DRAG; 
  146. System.out.println("MotionEvent--ACTION_DOWN"); 
  147. break
  148. case MotionEvent.ACTION_POINTER_DOWN: 
  149. oldDist = spacing(event); 
  150. oldRotation = rotation(event); 
  151. savedMatrix.set(matrix); 
  152. setMidPoint(pointM, event); 
  153. mode = ZOOM; 
  154. System.out.println("MotionEvent--ACTION_POINTER_DOWN---" + oldRotation); 
  155. break
  156. case MotionEvent.ACTION_UP: 
  157. if (mode == DRAG & (fingerNumMove this.finish(); 
  158. checkView(); 
  159. centerAndRotate(); 
  160. imageView.setImageMatrix(matrix); 
  161. System.out.println("MotionEvent--ACTION_UP"); 
  162. fingerNumMove = 0; 
  163. break
  164. case MotionEvent.ACTION_POINTER_UP: 
  165. mode = NONE; 
  166. System.out.println("MotionEvent--ACTION_POINTER_UP"); 
  167. break
  168. case MotionEvent.ACTION_MOVE: 
  169. operateMove(event); 
  170. imageView.setImageMatrix(matrix1); 
  171. fingerNumMove++; 
  172. System.out.println("MotionEvent--ACTION_MOVE"); 
  173. break
  174. return true
  175. @Override 
  176. protected void onDestroy() { 
  177. // TODO Auto-generated method stub 
  178. super.onDestroy(); 
  179. if (bm != null & !bm.isRecycled()) { 
  180. bm.recycle(); // 回收图片所占的内存 
  181. System.gc(); // 提醒系统及时回收 
  182. /** 
  183. * 显示图片 
  184. */ 
  185. private void showImage() { 
  186. imgWidth = bm.getWidth(); 
  187. imgHeight = bm.getHeight(); 
  188. mImageView.setImageBitmap(bm); 
  189. matrix.setScale(1, 1); 
  190. centerAndRotate(); 
  191. mImageView.setImageMatrix(matrix); 
  192. /** 
  193. * 触点移动时的操作 
  194. * 
  195. * @param event 触摸事件 
  196. */ 
  197. private void operateMove(MotionEvent event) { 
  198. matrix1.set(savedMatrix); 
  199. switch (mode) { 
  200. case DRAG: 
  201. matrix1.postTranslate(event.getX() - point0.x, event.getY() - point0.y); 
  202. break
  203. case ZOOM: 
  204. rotation = rotation(event) - oldRotation; 
  205. float newDist = spacing(event); 
  206. float scale = newDist / oldDist; 
  207. currentScale = (scale > 3.5f) ? 3.5f : scale; 
  208. System.out.println("缩放倍数---" + currentScale); 
  209. System.out.println("旋转角度---" + rotation); 
  210. /** 縮放 */ 
  211. matrix1.postScale(currentScale, currentScale, pointM.x, pointM.y); 
  212. /** 旋轉 */ 
  213. matrix1.postRotate(rotation, displayWidth / 2, displayHeight / 2); 
  214. break
  215. /** 
  216. * 两个触点的距离 
  217. * 
  218. * @param event 触摸事件 
  219. * @return float 
  220. */ 
  221. private float spacing(MotionEvent event) { 
  222. float x = event.getX(0) - event.getX(1); 
  223. float y = event.getY(0) - event.getY(1); 
  224. return (float) Math.sqrt(x * x + y * y); 
  225. /** 
  226. * 获取旋转角度 
  227. */ 
  228. private float rotation(MotionEvent event) { 
  229. double delta_x = (event.getX(0) - event.getX(1)); 
  230. double delta_y = (event.getY(0) - event.getY(1)); 
  231. double radians = Math.atan2(delta_y, delta_x); 
  232. return (float) Math.toDegrees(radians); 
  233. /** 
  234. * 两个触点的中间坐标 
  235. * 
  236. * @param pointM 中间坐标 
  237. * @param event 触摸事件 
  238. */ 
  239. private void setMidPoint(PointF pointM, MotionEvent event) { 
  240. float x = event.getX(0) + event.getY(1); 
  241. float y = event.getY(0) + event.getY(1); 
  242. pointM.set(x / 2, y / 2); 
  243. /** 
  244. * 检查约束条件(缩放倍数) 
  245. */ 
  246. private void checkView() { 
  247. if (currentScale > 1) { 
  248. if (currentScale * matrixScale > maxScale) { 
  249. matrix.postScale(maxScale / matrixScale, maxScale / matrixScale, pointM.x, pointM.y); 
  250. matrixScale = maxScale; 
  251. else { 
  252. matrix.postScale(currentScale, currentScale, pointM.x, pointM.y); 
  253. matrixScale *= currentScale; 
  254. else { 
  255. if (currentScale * matrixScale else { 
  256. matrix.postScale(currentScale, currentScale, pointM.x, pointM.y); 
  257. matrixScale *= currentScale; 
  258. /** 
  259. * 图片居中显示、判断旋转角度 小于(90 * x + 45)度图片旋转(90 * x)度 大于则旋转(90 * (x+1)) 
  260. */ 
  261. private void centerAndRotate() { 
  262. RectF rect = new RectF(0, 0, imgWidth, imgHeight); 
  263. matrix.mapRect(rect); 
  264. float width = rect.width(); 
  265. float height = rect.height(); 
  266. float dx = 0; 
  267. float dy = 0; 
  268. if (width 2 - width / 2 - rect.left; 
  269. else if (rect.left > 0) { 
  270. dx = -rect.left; 
  271. else if (rect.right if (height 2 - height / 2 - rect.top; 
  272. else if (rect.top > 0) { 
  273. dy = -rect.top; 
  274. else if (rect.bottom if (rotation != 0) { 
  275. int rotationNum = (int) (rotation / 90); 
  276. float rotationAvai = new BigDecimal(rotation % 90).setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); 
  277. float realRotation = 0; 
  278. if (rotation > 0) { 
  279. realRotation = rotationAvai > 45 ? (rotationNum + 1) * 90 : rotationNum * 90; 
  280. else if (rotation 0) { 
  281. realRotation = rotationAvai 45 ? (rotationNum - 1) * 90 : rotationNum * 90; 
  282. System.out.println("realRotation: " + realRotation); 
  283. matrix.postRotate(realRotation, displayWidth / 2, displayHeight / 2); 
  284. rotation = 0; 
  285. /** 
  286. * 显示网络图片时使用 
  287. */ 
  288. private class MyTask extends AsyncTaskFile, File, Bitmap> { 
  289. Bitmap bitmap; 
  290. String path; 
  291. int scale = 1; 
  292. long size; 
  293. @Override 
  294. protected Bitmap doInBackground(File... params) { 
  295. // TODO Auto-generated method stub 
  296. try { 
  297. size = params[0].length(); 
  298. path = params[0].getAbsolutePath(); 
  299. BitmapFactory.Options options = new BitmapFactory.Options(); 
  300. options.inJustDecodeBounds = true
  301. BitmapFactory.decodeFile(path, options); 
  302. scale = calculateInSampleSize(options, displayWidth, 
  303. displayHeight); 
  304. options.inJustDecodeBounds = false
  305. options.inSampleSize = scale; 
  306. bitmap = BitmapFactory.decodeFile(path, options); 
  307. catch (Exception e) { 
  308. // TODO Auto-generated catch block 
  309. e.printStackTrace(); 
  310. return bitmap; 
  311. @Override 
  312. protected void onPostExecute(Bitmap result) { 
  313. // TODO Auto-generated method stub 
  314. EventBus.getDefault().post( 
  315. new CustomEventBus(CustomEventBus.EventType.SHOW_PICTURE, result)); 
  316. /** 
  317. * 获取图片缩放比例 
  318. * 
  319. * @param paramOptions Options 
  320. * @param paramInt1 宽 
  321. * @param paramInt2 高 
  322. * @return int 
  323. */ 
  324. private int calculateInSampleSize(BitmapFactory.Options paramOptions, 
  325. int paramInt1, int paramInt2) { 
  326. int i = paramOptions.outHeight; 
  327. int j = paramOptions.outWidth; 
  328. int k = 1; 
  329. if ((i > paramInt2) || (j > paramInt1)) { 
  330. int m = Math.round(i / paramInt2); 
  331. int n = Math.round(j / paramInt1); 
  332. k = m return k; 
  333. CustomEventBus.java 
  334. package com.practice.noyet.rotatezoomimageview; 
  335. /** 
  336. * package: com.practice.noyet.rotatezoomimageview 
  337. * Created by noyet on 2015/11/11. 
  338. */ 
  339. public class CustomEventBus { 
  340. public EventType type; 
  341. public Object obj; 
  342. public CustomEventBus(EventType type, Object obj) { 
  343. this.type = type; 
  344. this.obj = obj; 
  345. enum EventType { 
  346. SHOW_PICTURE 


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表