博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
View实现涂鸦、撤销以及重做功能【转】
阅读量:6358 次
发布时间:2019-06-23

本文共 4601 字,大约阅读时间需要 15 分钟。

Java代码  
import java.io.File;  
import java.io.FileNotFoundException;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.util.ArrayList;  
import java.util.Iterator;  
import java.util.List;  
  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.Canvas;  
import android.graphics.Paint;  
import android.graphics.Path;  
import android.graphics.Bitmap.CompressFormat;  
import android.os.Environment;  
import android.view.MotionEvent;  
import android.view.View;  
  
/**
 
 * View实现涂鸦、撤销以及重做功能 
 
*/  
  
public 
class TuyaView 
extends View {  
  
    
private Bitmap mBitmap;  
    
private Canvas mCanvas;  
    
private Path mPath;  
    
private Paint mBitmapPaint;
//
 画布的画笔  
    
private Paint mPaint;
//
 真实的画笔  
    
private 
float mX, mY;
//
 临时点坐标  
    
private 
static 
final 
float TOUCH_TOLERANCE = 4;  
      
    
//
 保存Path路径的集合,用List集合来模拟栈  
    
private 
static List<DrawPath> savePath;  
    
//
 记录Path路径的对象  
    
private DrawPath dp;  
  
    
private 
int screenWidth, screenHeight;  
  
    
private 
class DrawPath {  
        
public Path path;
//
 路径  
        
public Paint paint;
//
 画笔  
    }  
  
    
public TuyaView(Context context, 
int w, 
int h) {  
        
super(context);  
        screenWidth = w;  
        screenHeight = h;  
  
        mBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);  
        
//
 保存一次一次绘制出来的图形  
        mCanvas = 
new Canvas(mBitmap);  
  
        mBitmapPaint = 
new Paint(Paint.DITHER_FLAG);  
        mPaint = 
new Paint();  
        mPaint.setAntiAlias(
true);  
        mPaint.setStyle(Paint.Style.STROKE);  
        mPaint.setStrokeJoin(Paint.Join.ROUND);
//
 设置外边缘  
        mPaint.setStrokeCap(Paint.Cap.ROUND);
//
 形状  
        mPaint.setStrokeWidth(5);
//
 画笔宽度  
  
        savePath = 
new ArrayList<DrawPath>();  
    }  
  
    @Override  
    
public 
void onDraw(Canvas canvas) {  
        canvas.drawColor(0xFFAAAAAA);  
        
//
 将前面已经画过得显示出来  
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);  
        
if (mPath != 
null) {  
            
//
 实时的显示  
            canvas.drawPath(mPath, mPaint);  
        }  
    }  
  
    
private 
void touch_start(
float x, 
float y) {  
        mPath.moveTo(x, y);  
        mX = x;  
        mY = y;  
    }  
  
    
private 
void touch_move(
float x, 
float y) {  
        
float dx = Math.abs(x - mX);  
        
float dy = Math.abs(mY - y);  
        
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {  
            
//
 从x1,y1到x2,y2画一条贝塞尔曲线,更平滑(直接用mPath.lineTo也是可以的)  
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);  
            mX = x;  
            mY = y;  
        }  
    }  
  
    
private 
void touch_up() {  
        mPath.lineTo(mX, mY);  
        mCanvas.drawPath(mPath, mPaint);  
        
//
将一条完整的路径保存下来(相当于入栈操作)  
        savePath.add(dp);  
        mPath = 
null;
//
 重新置空  
    }  
    
/**
 
     * 撤销的核心思想就是将画布清空, 
     * 将保存下来的Path路径最后一个移除掉, 
     * 重新将路径画在画布上面。 
     
*/  
    
public 
void undo() {  
        
if (savePath != 
null && savePath.size() > 0) {  
            savePath.remove(savePath.size() - 1);  
            redrawOnBitmap();  
        }  
    }  
    
/**
 
     * 重做 
     
*/  
    
public 
void redo(){  
        
if (savePath != 
null && savePath.size() > 0) {  
            savePath.clear();  
            redrawOnBitmap();  
        }  
    }  
      
    
private 
void redrawOnBitmap(){  
        mBitmap = Bitmap.createBitmap(screenWidth, screenHeight,  
                Bitmap.Config.ARGB_8888);  
        mCanvas.setBitmap(mBitmap);
//
 重新设置画布,相当于清空画布   
        Iterator<DrawPath> iter = savePath.iterator();  
        
while (iter.hasNext()) {  
            DrawPath drawPath = iter.next();  
            mCanvas.drawPath(drawPath.path, drawPath.paint);  
        }  
        invalidate();
//
 刷新  
    }  
  
    @Override  
    
public 
boolean onTouchEvent(MotionEvent event) {  
        
float x = event.getX();  
        
float y = event.getY();  
  
        
switch (event.getAction()) {  
        
case MotionEvent.ACTION_DOWN:  
            
//
 每次down下去重新new一个Path  
            mPath = 
new Path();  
            
//
每一次记录的路径对象是不一样的  
            dp = 
new DrawPath();  
            dp.path = mPath;  
            dp.paint = mPaint;  
            touch_start(x, y);  
            invalidate();  
            
break;  
        
case MotionEvent.ACTION_MOVE:  
            touch_move(x, y);  
            invalidate();  
            
break;  
        
case MotionEvent.ACTION_UP:  
            touch_up();  
            invalidate();  
            
break;  
        }  
        
return 
true;  
    }  
  
    
public 
void saveToSDCard(){  
        String fileUrl = Environment.getExternalStorageDirectory()  
                .toString() + "/android/data/test.png";  
        
try {  
            FileOutputStream fos = 
new FileOutputStream(
new File(fileUrl));  
            mBitmap.compress(CompressFormat.PNG, 100, fos);  
            fos.flush();  
            fos.close();  
        } 
catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } 
catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}  
Java代码  
import android.app.Activity;  
import android.os.Bundle;  
import android.util.DisplayMetrics;  
import android.util.Log;  
import android.view.KeyEvent;  
  
public 
class TuyaActivity 
extends Activity {  
  
    
private TuyaView tuyaView = 
null;  
  
    @Override  
    
public 
void onCreate(Bundle savedInstanceState) {  
        
super.onCreate(savedInstanceState);  
  
        DisplayMetrics dm = 
new DisplayMetrics();  
        getWindowManager().getDefaultDisplay().getMetrics(dm);  
  
        tuyaView = 
new TuyaView(
this, dm.widthPixels, dm.heightPixels);  
        setContentView(tuyaView);  
    }  
  
    @Override  
    
public 
boolean onKeyDown(
int keyCode, KeyEvent event) {  
        
if (keyCode == KeyEvent.KEYCODE_BACK) {
//
 返回键  
            tuyaView.undo();  
            
return 
true;  
        }
else 
if(keyCode == KeyEvent.KEYCODE_MENU){
//
MENU  
            tuyaView.redo();  
            
return 
true;  
        }  
        
return 
super.onKeyDown(keyCode, event);  
    }  
  

 

 //原文地址:http://www.cnblogs.com/top5/archive/2012/04/09/2439626.html

你可能感兴趣的文章
Optional
查看>>
sed 命令编辑文本
查看>>
Activity调用isDestroyed()方法报出,java.lang.NoSuchMethodError
查看>>
使用AFNetworking第三方下载类
查看>>
fhq-treap小结
查看>>
about porting
查看>>
MySQL事务及ACID特性
查看>>
Hadoop_31_MapReduce参数优化
查看>>
linux运维常见英文报错中文翻译(菜鸟必知)
查看>>
[原][osgEarth]添加自由飞行漫游器
查看>>
fastjson如何指定字段不序列化
查看>>
[日常] Go语言圣经--示例: 并发的Echo服务
查看>>
BZOJ1969: [Ahoi2005]LANE 航线规划(LCT)
查看>>
linux内存管理之malloc、vmalloc、kmalloc的区别
查看>>
GreenDao 数据库升级 连接多个DB文件 或者指定不同的model&dao目录
查看>>
M1卡破解(自从学校升级系统之后,还准备在研究下)【转】
查看>>
vue 访问子组件示例 或者子元素
查看>>
linux内核--自旋锁的理解
查看>>
银行卡的三个磁道
查看>>
OpenSSL 提取 pfx 数字证书公钥与私钥
查看>>