当前位置:   article > 正文

Android手写文字(涂鸦)_android米聊手写

android米聊手写

本文转自:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=173234

类似米聊、微信上的涂鸦和手写文字功能
实现原理是自定义View,通过手势识别获取轨迹,然后通过画笔画图
这里添加了手势记录功能,并不难理解
代码贴下
  1. public class TuyaView extends View {
  2. private Bitmap mBitmap;
  3. private Canvas mCanvas;
  4. private Path mPath;
  5. private Paint mBitmapPaint;// 画布的画笔
  6. private Paint mPaint;// 真实的画笔
  7. private float mX, mY;// 临时点坐标
  8. private static final float TOUCH_TOLERANCE = 4;
  9. // 保存Path路径的集合,用List集合来模拟栈
  10. private static List<DrawPath> savePath;
  11. // 记录Path路径的对象
  12. private DrawPath dp;
  13. private int screenWidth, screenHeight;// 屏幕長寬
  14. private class DrawPath {
  15. public Path path;// 路径
  16. public Paint paint;// 画笔
  17. }
  18. public TuyaView(Context context, int w, int h) {
  19. super(context);
  20. screenWidth = w;
  21. screenHeight = h;
  22. mBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);
  23. // 保存一次一次绘制出来的图形
  24. mCanvas = new Canvas(mBitmap);
  25. mBitmapPaint = new Paint(Paint.DITHER_FLAG);
  26. mPaint = new Paint();
  27. mPaint.setAntiAlias(true);
  28. mPaint.setStyle(Paint.Style.STROKE);
  29. mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
  30. mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形状
  31. mPaint.setStrokeWidth(5);// 画笔宽度
  32. savePath = new ArrayList<DrawPath>();
  33. }
  34. @Override
  35. public void onDraw(Canvas canvas) {
  36. canvas.drawColor(0xFFAAAAAA);
  37. // 将前面已经画过得显示出来
  38. canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
  39. if (mPath != null) {
  40. // 实时的显示
  41. canvas.drawPath(mPath, mPaint);
  42. }
  43. }
  44. private void touch_start(float x, float y) {
  45. mPath.moveTo(x, y);
  46. mX = x;
  47. mY = y;
  48. }
  49. private void touch_move(float x, float y) {
  50. float dx = Math.abs(x - mX);
  51. float dy = Math.abs(mY - y);
  52. if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
  53. // 从x1,y1到x2,y2画一条贝塞尔曲线,更平滑(直接用mPath.lineTo也是可以的)
  54. mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
  55. mX = x;
  56. mY = y;
  57. }
  58. }
  59. private void touch_up() {
  60. mPath.lineTo(mX, mY);
  61. mCanvas.drawPath(mPath, mPaint);
  62. //将一条完整的路径保存下来(相当于入栈操作)
  63. savePath.add(dp);
  64. mPath = null;// 重新置空
  65. }
  66. /**
  67. * 撤销的核心思想就是将画布清空,
  68. * 将保存下来的Path路径最后一个移除掉,
  69. * 重新将路径画在画布上面。
  70. */
  71. public void undo() {
  72. mBitmap = Bitmap.createBitmap(screenWidth, screenHeight,
  73. Bitmap.Config.ARGB_8888);
  74. mCanvas.setBitmap(mBitmap);// 重新设置画布,相当于清空画布
  75. // 清空画布,但是如果图片有背景的话,则使用上面的重新初始化的方法,用该方法会将背景清空掉...
  76. if (savePath != null && savePath.size() > 0) {
  77. // 移除最后一个path,相当于出栈操作
  78. savePath.remove(savePath.size() - 1);
  79. Iterator<DrawPath> iter = savePath.iterator();
  80. while (iter.hasNext()) {
  81. DrawPath drawPath = iter.next();
  82. mCanvas.drawPath(drawPath.path, drawPath.paint);
  83. }
  84. invalidate();// 刷新
  85. /*在这里保存图片纯粹是为了方便,保存图片进行验证*/
  86. String fileUrl = Environment.getExternalStorageDirectory()
  87. .toString() + "/android/data/test.png";
  88. try {
  89. FileOutputStream fos = new FileOutputStream(new File(fileUrl));
  90. mBitmap.compress(CompressFormat.PNG, 100, fos);
  91. fos.flush();
  92. fos.close();
  93. } catch (FileNotFoundException e) {
  94. e.printStackTrace();
  95. } catch (IOException e) {
  96. e.printStackTrace();
  97. }
  98. }
  99. }
  100. /**
  101. * 重做的核心思想就是将撤销的路径保存到另外一个集合里面(栈),
  102. * 然后从redo的集合里面取出最顶端对象,
  103. * 画在画布上面即可。
  104. */
  105. public void redo(){
  106. //如果撤销你懂了的话,那就试试重做吧。
  107. }
  108. @Override
  109. public boolean onTouchEvent(MotionEvent event) {
  110. float x = event.getX();
  111. float y = event.getY();
  112. switch (event.getAction()) {
  113. case MotionEvent.ACTION_DOWN:
  114. // 每次down下去重新new一个Path
  115. mPath = new Path();
  116. //每一次记录的路径对象是不一样的
  117. dp = new DrawPath();
  118. dp.path = mPath;
  119. dp.paint = mPaint;
  120. touch_start(x, y);
  121. invalidate();
  122. break;
  123. case MotionEvent.ACTION_MOVE:
  124. touch_move(x, y);
  125. invalidate();
  126. break;
  127. case MotionEvent.ACTION_UP:
  128. touch_up();
  129. invalidate();
  130. break;
  131. }
  132. return true;
  133. }
  134. }

调用地方
  1. public class TuyaActivity extends Activity {
  2. private TuyaView tuyaView = null;
  3. @Override
  4. public void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. DisplayMetrics dm = new DisplayMetrics();
  7. getWindowManager().getDefaultDisplay().getMetrics(dm);
  8. tuyaView = new TuyaView(this, dm.widthPixels, dm.heightPixels);
  9. setContentView(tuyaView);
  10. }
  11. @Override
  12. public boolean onKeyDown(int keyCode, KeyEvent event) {
  13. if (keyCode == KeyEvent.KEYCODE_BACK) {// 返回键
  14. tuyaView.undo();
  15. return true;
  16. }
  17. return super.onKeyDown(keyCode, event);
  18. }
  19. }



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/598695
推荐阅读
相关标签
  

闽ICP备14008679号