zoukankan      html  css  js  c++  java
  • View实现涂鸦、撤销以及重做功能

    1. import java.io.File;  
    2. import java.io.FileNotFoundException;  
    3. import java.io.FileOutputStream;  
    4. import java.io.IOException;  
    5. import java.util.ArrayList;  
    6. import java.util.Iterator;  
    7. import java.util.List;  
    8.   
    9. import android.content.Context;  
    10. import android.graphics.Bitmap;  
    11. import android.graphics.Canvas;  
    12. import android.graphics.Paint;  
    13. import android.graphics.Path;  
    14. import android.graphics.Bitmap.CompressFormat;  
    15. import android.os.Environment;  
    16. import android.view.MotionEvent;  
    17. import android.view.View;  
    18.   
    19. /** 
    20.  * View实现涂鸦、撤销以及重做功能 
    21.  */  
    22.   
    23. public class TuyaView extends View {  
    24.   
    25.     private Bitmap mBitmap;  
    26.     private Canvas mCanvas;  
    27.     private Path mPath;  
    28.     private Paint mBitmapPaint;// 画布的画笔  
    29.     private Paint mPaint;// 真实的画笔  
    30.     private float mX, mY;// 临时点坐标  
    31.     private static final float TOUCH_TOLERANCE = 4;  
    32.       
    33.     // 保存Path路径的集合,用List集合来模拟栈  
    34.     private static List<DrawPath> savePath;  
    35.     // 记录Path路径的对象  
    36.     private DrawPath dp;  
    37.   
    38.     private int screenWidth, screenHeight;  
    39.   
    40.     private class DrawPath {  
    41.         public Path path;// 路径  
    42.         public Paint paint;// 画笔  
    43.     }  
    44.   
    45.     public TuyaView(Context context, int w, int h) {  
    46.         super(context);  
    47.         screenWidth = w;  
    48.         screenHeight = h;  
    49.   
    50.         mBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);  
    51.         // 保存一次一次绘制出来的图形  
    52.         mCanvas = new Canvas(mBitmap);  
    53.   
    54.         mBitmapPaint = new Paint(Paint.DITHER_FLAG);  
    55.         mPaint = new Paint();  
    56.         mPaint.setAntiAlias(true);  
    57.         mPaint.setStyle(Paint.Style.STROKE);  
    58.         mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘  
    59.         mPaint.setStrokeCap(Paint.Cap.ROUND);// 形状  
    60.         mPaint.setStrokeWidth(5);// 画笔宽度  
    61.   
    62.         savePath = new ArrayList<DrawPath>();  
    63.     }  
    64.   
    65.     @Override  
    66.     public void onDraw(Canvas canvas) {  
    67.         canvas.drawColor(0xFFAAAAAA);  
    68.         // 将前面已经画过得显示出来  
    69.         canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);  
    70.         if (mPath != null) {  
    71.             // 实时的显示  
    72.             canvas.drawPath(mPath, mPaint);  
    73.         }  
    74.     }  
    75.   
    76.     private void touch_start(float x, float y) {  
    77.         mPath.moveTo(x, y);  
    78.         mX = x;  
    79.         mY = y;  
    80.     }  
    81.   
    82.     private void touch_move(float x, float y) {  
    83.         float dx = Math.abs(x - mX);  
    84.         float dy = Math.abs(mY - y);  
    85.         if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {  
    86.             // 从x1,y1到x2,y2画一条贝塞尔曲线,更平滑(直接用mPath.lineTo也是可以的)  
    87.             mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);  
    88.             mX = x;  
    89.             mY = y;  
    90.         }  
    91.     }  
    92.   
    93.     private void touch_up() {  
    94.         mPath.lineTo(mX, mY);  
    95.         mCanvas.drawPath(mPath, mPaint);  
    96.         //将一条完整的路径保存下来(相当于入栈操作)  
    97.         savePath.add(dp);  
    98.         mPath = null;// 重新置空  
    99.     }  
    100.     /** 
    101.      * 撤销的核心思想就是将画布清空, 
    102.      * 将保存下来的Path路径最后一个移除掉, 
    103.      * 重新将路径画在画布上面。 
    104.      */  
    105.     public void undo() {  
    106.         if (savePath != null && savePath.size() > 0) {  
    107.             savePath.remove(savePath.size() - 1);  
    108.             redrawOnBitmap();  
    109.         }  
    110.     }  
    111.     /** 
    112.      * 重做 
    113.      */  
    114.     public void redo(){  
    115.         if (savePath != null && savePath.size() > 0) {  
    116.             savePath.clear();  
    117.             redrawOnBitmap();  
    118.         }  
    119.     }  
    120.       
    121.     private void redrawOnBitmap(){  
    122.         mBitmap = Bitmap.createBitmap(screenWidth, screenHeight,  
    123.                 Bitmap.Config.ARGB_8888);  
    124.         mCanvas.setBitmap(mBitmap);// 重新设置画布,相当于清空画布   
    125.         Iterator<DrawPath> iter = savePath.iterator();  
    126.         while (iter.hasNext()) {  
    127.             DrawPath drawPath = iter.next();  
    128.             mCanvas.drawPath(drawPath.path, drawPath.paint);  
    129.         }  
    130.         invalidate();// 刷新  
    131.     }  
    132.   
    133.     @Override  
    134.     public boolean onTouchEvent(MotionEvent event) {  
    135.         float x = event.getX();  
    136.         float y = event.getY();  
    137.   
    138.         switch (event.getAction()) {  
    139.         case MotionEvent.ACTION_DOWN:  
    140.             // 每次down下去重新new一个Path  
    141.             mPath = new Path();  
    142.             //每一次记录的路径对象是不一样的  
    143.             dp = new DrawPath();  
    144.             dp.path = mPath;  
    145.             dp.paint = mPaint;  
    146.             touch_start(x, y);  
    147.             invalidate();  
    148.             break;  
    149.         case MotionEvent.ACTION_MOVE:  
    150.             touch_move(x, y);  
    151.             invalidate();  
    152.             break;  
    153.         case MotionEvent.ACTION_UP:  
    154.             touch_up();  
    155.             invalidate();  
    156.             break;  
    157.         }  
    158.         return true;  
    159.     }  
    160.   
    161.     public void saveToSDCard(){  
    162.         String fileUrl = Environment.getExternalStorageDirectory()  
    163.                 .toString() + "/android/data/test.png";  
    164.         try {  
    165.             FileOutputStream fos = new FileOutputStream(new File(fileUrl));  
    166.             mBitmap.compress(CompressFormat.PNG, 100, fos);  
    167.             fos.flush();  
    168.             fos.close();  
    169.         } catch (FileNotFoundException e) {  
    170.             e.printStackTrace();  
    171.         } catch (IOException e) {  
    172.             e.printStackTrace();  
    173.         }  
    174.     }  
    175. }  


    Java代码  收藏代码
    1. import android.app.Activity;  
    2. import android.os.Bundle;  
    3. import android.util.DisplayMetrics;  
    4. import android.util.Log;  
    5. import android.view.KeyEvent;  
    6.   
    7. public class TuyaActivity extends Activity {  
    8.   
    9.     private TuyaView tuyaView = null;  
    10.   
    11.     @Override  
    12.     public void onCreate(Bundle savedInstanceState) {  
    13.         super.onCreate(savedInstanceState);  
    14.   
    15.         DisplayMetrics dm = new DisplayMetrics();  
    16.         getWindowManager().getDefaultDisplay().getMetrics(dm);  
    17.   
    18.         tuyaView = new TuyaView(this, dm.widthPixels, dm.heightPixels);  
    19.         setContentView(tuyaView);  
    20.     }  
    21.   
    22.     @Override  
    23.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
    24.         if (keyCode == KeyEvent.KEYCODE_BACK) {// 返回键  
    25.             tuyaView.undo();  
    26.             return true;  
    27.         }else if(keyCode == KeyEvent.KEYCODE_MENU){//MENU  
    28.             tuyaView.redo();  
    29.             return true;  
    30.         }  
    31.         return super.onKeyDown(keyCode, event);  
    32.     }  
    33.   
    34. }  


     
    • Tuya.rar (234.4 KB)
    • 下载次数: 202
  • 相关阅读:
    Java反编译代码分析(一)
    Java信号量Semaphore
    Ubuntu SVN安装&使用&命令
    Android -- Dialog动画
    Android -- EventBus使用
    Android -- queryIntentActivities
    解决:fatal: authentication failed for https
    MySQL表名大小写敏感导致的问题
    Publish to a Linux Production Environment
    layer.js 弹窗组件API文档
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4750391.html
Copyright © 2011-2022 走看看