首页 > 系统 > 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. } 
  114. if (event.type == CustomEventBus.EventType.SHOW_PICTURE) { 
  115. bm = (Bitmap) event.obj; 
  116. showImage(); 
  117. } 
  118. } 
  119. @Override 
  120. protected void onCreate(Bundle savedInstanceState) { 
  121. super.onCreate(savedInstanceState); 
  122. setContentView(R.layout.activity_main); 
  123. initData(); 
  124. } 
  125. public void initData() { 
  126. // TODO Auto-generated method stub 
  127. bm = BitmapFactory.decodeResource(getResources(), R.drawable.alipay); 
  128. DisplayMetrics dm = getResources().getDisplayMetrics(); 
  129. displayWidth = dm.widthPixels; 
  130. displayHeight = dm.heightPixels; 
  131. mImageView = (ImageView) findViewById(R.id.image_view); 
  132. mImageView.setOnTouchListener(this); 
  133. showImage(); 
  134. //显示网络图片时使用 
  135. /*File file = MainApplication.getInstance().getImageCache() 
  136. .getDiskCache().get(图片路径); 
  137. if (!file.exists()) { 
  138. Toast.makeText(this, "图片路径错误", Toast.LENGTH_SHORT).show(); 
  139. } else { 
  140. new MyTask().execute(file); 
  141. }*/ 
  142. } 
  143. @Override 
  144. public boolean onTouch(View view, MotionEvent event) { 
  145. ImageView imageView = (ImageView) view; 
  146. switch (event.getAction() & MotionEvent.ACTION_MASK) { 
  147. case MotionEvent.ACTION_DOWN: 
  148. savedMatrix.set(matrix); 
  149. point0.set(event.getX(), event.getY()); 
  150. mode = DRAG; 
  151. System.out.println("MotionEvent--ACTION_DOWN"); 
  152. break; 
  153. case MotionEvent.ACTION_POINTER_DOWN: 
  154. oldDist = spacing(event); 
  155. oldRotation = rotation(event); 
  156. savedMatrix.set(matrix); 
  157. setMidPoint(pointM, event); 
  158. mode = ZOOM; 
  159. System.out.println("MotionEvent--ACTION_POINTER_DOWN---" + oldRotation); 
  160. break; 
  161. case MotionEvent.ACTION_UP: 
  162. if (mode == DRAG & (fingerNumMove this.finish(); 
  163. } 
  164. checkView(); 
  165. centerAndRotate(); 
  166. imageView.setImageMatrix(matrix); 
  167. System.out.println("MotionEvent--ACTION_UP"); 
  168. fingerNumMove = 0; 
  169. break; 
  170. case MotionEvent.ACTION_POINTER_UP: 
  171. mode = NONE; 
  172. System.out.println("MotionEvent--ACTION_POINTER_UP"); 
  173. break; 
  174. case MotionEvent.ACTION_MOVE: 
  175. operateMove(event); 
  176. imageView.setImageMatrix(matrix1); 
  177. fingerNumMove++; 
  178. System.out.println("MotionEvent--ACTION_MOVE"); 
  179. break; 
  180. } 
  181. return true; 
  182. } 
  183. @Override 
  184. protected void onDestroy() { 
  185. // TODO Auto-generated method stub 
  186. super.onDestroy(); 
  187. if (bm != null & !bm.isRecycled()) { 
  188. bm.recycle(); // 回收图片所占的内存 
  189. System.gc(); // 提醒系统及时回收 
  190. } 
  191. } 
  192. /** 
  193. * 显示图片 
  194. */ 
  195. private void showImage() { 
  196. imgWidth = bm.getWidth(); 
  197. imgHeight = bm.getHeight(); 
  198. mImageView.setImageBitmap(bm); 
  199. matrix.setScale(1, 1); 
  200. centerAndRotate(); 
  201. mImageView.setImageMatrix(matrix); 
  202. } 
  203. /** 
  204. * 触点移动时的操作 
  205. * 
  206. * @param event 触摸事件 
  207. */ 
  208. private void operateMove(MotionEvent event) { 
  209. matrix1.set(savedMatrix); 
  210. switch (mode) { 
  211. case DRAG: 
  212. matrix1.postTranslate(event.getX() - point0.x, event.getY() - point0.y); 
  213. break; 
  214. case ZOOM: 
  215. rotation = rotation(event) - oldRotation; 
  216. float newDist = spacing(event); 
  217. float scale = newDist / oldDist; 
  218. currentScale = (scale > 3.5f) ? 3.5f : scale; 
  219. System.out.println("缩放倍数---" + currentScale); 
  220. System.out.println("旋转角度---" + rotation); 
  221. /** 縮放 */ 
  222. matrix1.postScale(currentScale, currentScale, pointM.x, pointM.y); 
  223. /** 旋轉 */ 
  224. matrix1.postRotate(rotation, displayWidth / 2, displayHeight / 2); 
  225. break; 
  226. } 
  227. } 
  228. /** 
  229. * 两个触点的距离 
  230. * 
  231. * @param event 触摸事件 
  232. * @return float 
  233. */ 
  234. private float spacing(MotionEvent event) { 
  235. float x = event.getX(0) - event.getX(1); 
  236. float y = event.getY(0) - event.getY(1); 
  237. return (float) Math.sqrt(x * x + y * y); 
  238. } 
  239. /** 
  240. * 获取旋转角度 
  241. */ 
  242. private float rotation(MotionEvent event) { 
  243. double delta_x = (event.getX(0) - event.getX(1)); 
  244. double delta_y = (event.getY(0) - event.getY(1)); 
  245. double radians = Math.atan2(delta_y, delta_x); 
  246. return (float) Math.toDegrees(radians); 
  247. } 
  248. /** 
  249. * 两个触点的中间坐标 
  250. * 
  251. * @param pointM 中间坐标 
  252. * @param event 触摸事件 
  253. */ 
  254. private void setMidPoint(PointF pointM, MotionEvent event) { 
  255. float x = event.getX(0) + event.getY(1); 
  256. float y = event.getY(0) + event.getY(1); 
  257. pointM.set(x / 2, y / 2); 
  258. } 
  259. /** 
  260. * 检查约束条件(缩放倍数) 
  261. */ 
  262. private void checkView() { 
  263. if (currentScale > 1) { 
  264. if (currentScale * matrixScale > maxScale) { 
  265. matrix.postScale(maxScale / matrixScale, maxScale / matrixScale, pointM.x, pointM.y); 
  266. matrixScale = maxScale; 
  267. } else { 
  268. matrix.postScale(currentScale, currentScale, pointM.x, pointM.y); 
  269. matrixScale *= currentScale; 
  270. } 
  271. } else { 
  272. if (currentScale * matrixScale else { 
  273. matrix.postScale(currentScale, currentScale, pointM.x, pointM.y); 
  274. matrixScale *= currentScale; 
  275. } 
  276. } 
  277. } 
  278. /** 
  279. * 图片居中显示、判断旋转角度 小于(90 * x + 45)度图片旋转(90 * x)度 大于则旋转(90 * (x+1)) 
  280. */ 
  281. private void centerAndRotate() { 
  282. RectF rect = new RectF(0, 0, imgWidth, imgHeight); 
  283. matrix.mapRect(rect); 
  284. float width = rect.width(); 
  285. float height = rect.height(); 
  286. float dx = 0; 
  287. float dy = 0; 
  288. if (width 2 - width / 2 - rect.left; 
  289. } else if (rect.left > 0) { 
  290. dx = -rect.left; 
  291. } else if (rect.right if (height 2 - height / 2 - rect.top; 
  292. } else if (rect.top > 0) { 
  293. dy = -rect.top; 
  294. } else if (rect.bottom if (rotation != 0) { 
  295. int rotationNum = (int) (rotation / 90); 
  296. float rotationAvai = new BigDecimal(rotation % 90).setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); 
  297. float realRotation = 0; 
  298. if (rotation > 0) { 
  299. realRotation = rotationAvai > 45 ? (rotationNum + 1) * 90 : rotationNum * 90; 
  300. } else if (rotation 0) { 
  301. realRotation = rotationAvai 45 ? (rotationNum - 1) * 90 : rotationNum * 90; 
  302. } 
  303. System.out.println("realRotation: " + realRotation); 
  304. matrix.postRotate(realRotation, displayWidth / 2, displayHeight / 2); 
  305. rotation = 0; 
  306. } 
  307. } 
  308. /** 
  309. * 显示网络图片时使用 
  310. */ 
  311. private class MyTask extends AsyncTaskFile, File, Bitmap> { 
  312. Bitmap bitmap; 
  313. String path; 
  314. int scale = 1; 
  315. long size; 
  316. @Override 
  317. protected Bitmap doInBackground(File... params) { 
  318. // TODO Auto-generated method stub 
  319. try { 
  320. size = params[0].length(); 
  321. path = params[0].getAbsolutePath(); 
  322. BitmapFactory.Options options = new BitmapFactory.Options(); 
  323. options.inJustDecodeBounds = true; 
  324. BitmapFactory.decodeFile(path, options); 
  325. scale = calculateInSampleSize(options, displayWidth, 
  326. displayHeight); 
  327. options.inJustDecodeBounds = false; 
  328. options.inSampleSize = scale; 
  329. bitmap = BitmapFactory.decodeFile(path, options); 
  330. } catch (Exception e) { 
  331. // TODO Auto-generated catch block 
  332. e.printStackTrace(); 
  333. } 
  334. return bitmap; 
  335. } 
  336. @Override 
  337. protected void onPostExecute(Bitmap result) { 
  338. // TODO Auto-generated method stub 
  339. EventBus.getDefault().post( 
  340. new CustomEventBus(CustomEventBus.EventType.SHOW_PICTURE, result)); 
  341. } 
  342. /** 
  343. * 获取图片缩放比例 
  344. * 
  345. * @param paramOptions Options 
  346. * @param paramInt1 宽 
  347. * @param paramInt2 高 
  348. * @return int 
  349. */ 
  350. private int calculateInSampleSize(BitmapFactory.Options paramOptions, 
  351. int paramInt1, int paramInt2) { 
  352. int i = paramOptions.outHeight; 
  353. int j = paramOptions.outWidth; 
  354. int k = 1; 
  355. if ((i > paramInt2) || (j > paramInt1)) { 
  356. int m = Math.round(i / paramInt2); 
  357. int n = Math.round(j / paramInt1); 
  358. k = m return k; 
  359. } 
  360. } 
  361. } 
  362. CustomEventBus.java 
  363. package com.practice.noyet.rotatezoomimageview; 
  364. /** 
  365. * package: com.practice.noyet.rotatezoomimageview 
  366. * Created by noyet on 2015/11/11. 
  367. */ 
  368. public class CustomEventBus { 
  369. public EventType type; 
  370. public Object obj; 
  371. public CustomEventBus(EventType type, Object obj) { 
  372. this.type = type; 
  373. this.obj = obj; 
  374. } 
  375. enum EventType { 
  376. SHOW_PICTURE 
  377. } 
  378. } 


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