现在的位置: 首页 > 综合 > 正文

简单笔画轨迹的绘制,并通过保存轨迹点,实现Path的保存和恢复。

2013年09月20日 ⁄ 综合 ⁄ 共 8247字 ⁄ 字号 评论关闭

保存画板中绘制的轨迹,有两种方法:

1.给canvas设置Bitmap,将轨迹等绘制在Bitmap上,在保存图片即可;下次重新进入模块时,加载图片到Bitmap,再通过canvas绘制出来即可。

2.只保存轨迹点,下次进入进入时重新绘制;

方法1,当图片很大时,容易出现OOM异常,这个很难避免。而方法2,可以避免OOM的问题。

下面的代码是按照方法2来实现的,

工程源码:

http://download.csdn.net/detail/victoryckl/4519210

效果图:

绘制时通过在onTouchEvent()中,记录触摸点,生成Path,在onDraw()绘制即可。

package org.ckl.path;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView;

public class MyView extends ImageView {

	private static final String TAG = "MyView";
	private List<PathAndPaint> mPaths = new ArrayList<PathAndPaint>();//保存每条轨迹的Path和Paint,便于绘制,不可序列化
	private Path mPath = new Path();
	private Paint mPaint = new Paint();
	private PathInfo mPathInfo;//保存每条轨迹的点坐标,可序列化,便于保存到文件

	private int[] mColors = new int[]{Color.BLACK, Color.RED, Color.GREEN, Color.BLUE, Color.CYAN, Color.YELLOW};
	
	
	private void init() {
		Log.i(TAG, "init()");
		mPaint.setAntiAlias(true);
		mPaint.setColor(Color.BLACK);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeWidth(3);
	}
	
	public MyView(Context context) {
		super(context);
		init();
	}

	public MyView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public MyView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	
	public void setPathInfo(PathInfo info) {
		mPath = new Path();
		mPathInfo = info;
		mPaths = mPathInfo.transfer();
		invalidate();
	}
	
	private int getColor() {
		int index = (int) (Math.round(Math.random() * mColors.length) % mColors.length);
		return mColors[index];
	}
	
	private boolean mHasMove = false;
	private float mX,mY;
	public boolean onTouchEvent(MotionEvent e) {
		boolean ret = false;
		switch (e.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mHasMove = false;
			mX = e.getX();
			mY = e.getY();
			mPaint.setColor(getColor());
			mPath.reset();
			mPath.moveTo(mX, mY);
			if (mPathInfo != null) {
				mPathInfo.lineStart(mX, mY);
			}
//			Log.i(TAG, "mPath.moveTo("+mX+"f,"+mY+"f);");
			invalidate();
			ret = true;
			break;
		case MotionEvent.ACTION_UP:
			mX = e.getX();
			mY = e.getY();
			mPath.lineTo(mX, mY);
			if (mPathInfo != null && mHasMove) {
				mPathInfo.lineEnd(mX, mY, mPaint.getColor());
			}
//			Log.i(TAG, "mPath.lineTo("+mX+"f,"+mY+"f);");
			mPaths.add(new PathAndPaint(new Path(mPath), new Paint(mPaint)));
			invalidate();
			ret = true;
			break;
		case MotionEvent.ACTION_MOVE:
			mHasMove = true;
			float x = e.getX();
			float y = e.getY();
			mPath.quadTo(mX, mY, (mX + x)/2, (mY + y)/2);
			if (mPathInfo != null) {
				mPathInfo.lineMove(x, y);
			}
//			Log.i(TAG, "mPath.quadTo("+mX+"f,"+mY+"f,"+(mX + x)/2+"f,"+(mY + y)/2+"f);");
			mX = x;
			mY = y;
			ret = true;
			invalidate();
			break;
		default:
			ret = super.onTouchEvent(e);
			break;
		}
		return ret;
	}

	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (PathAndPaint pp : mPaths) {
			canvas.drawPath(pp.getPath(), pp.getPaint());
		}
		canvas.drawPath(mPath, mPaint);
	}
}

在android中,android.graphics.Path是不可序列化的,所以不能直接通过ObjectOutputStream保存。

这里用PathAndPaint保存每条轨迹的Path和Paint,便于绘制,不可序列化,PathAndPaint实现如下:

package org.ckl.path;

import android.graphics.Paint;
import android.graphics.Path;

public class PathAndPaint {
	private Path mPath;
	private Paint mPaint;
	
	public PathAndPaint(Path path, Paint paint) {
		mPath = path;
		mPaint = paint;
	}
	public Path getPath() {
		return mPath;
	}
	public Paint getPaint() {
		return mPaint;
	}
}

PathInfo是轨迹的可以序列化表示,为每条轨迹保存颜色和一系列的坐标点,并实现保存到文件,从文件加载,及通过这些信息恢复PathAndPaint的功能:

package org.ckl.path;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.List;

import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.Log;

public class PathInfo implements Serializable {
	private static final long serialVersionUID = -5568568529548959041L;
	private static final String TAG = "PathInfo";

	class SerPoint implements Serializable {
		private static final long serialVersionUID = -2262755099592284491L;

		private float x;
		private float y;

		public SerPoint(float x, float y) {
			this.x = x;
			this.y = y;
		}
	}
	
	class SerPath implements Serializable {
		private static final long serialVersionUID = -900016536427010833L;
		private int mColor = Color.BLACK;
		private List<SerPoint> mPoints = new ArrayList<SerPoint>();
	}
	
	List<SerPath> mSerPaths = new ArrayList<PathInfo.SerPath>();
	
	private SerPath mCurPath;
	public void lineStart(float x, float y) {
		mCurPath = new SerPath();
		mCurPath.mPoints.add(new SerPoint(x, y));
	}
	public void lineMove(float x, float y) {
		mCurPath.mPoints.add(new SerPoint(x, y));
	}
	public void lineEnd(float x, float y, int color) {
		mCurPath.mPoints.add(new SerPoint(x, y));
		mCurPath.mColor = color;
		mSerPaths.add(mCurPath);
	}
	
	
	private PathInfo() {}
	//-转换为 PathAndPaint -------------------------------
	private Paint transferPaint(SerPath sp) {
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeWidth(3);
		paint.setColor(sp.mColor);
		return paint;
	}
	private Path transferPath(SerPath sp) {
		Path path = new Path();
		SerPoint p;
		int size = sp.mPoints.size();
		
		if (size < 3) {
			return path;
		}
		
		p = sp.mPoints.get(0);
		path.moveTo(p.x, p.y);
		
		float ox = p.x;
		float oy = p.y;
		
		for (int i = 1; i < size-1; i++) {
			p = sp.mPoints.get(i);
			path.quadTo(ox, oy, (ox + p.x)/2, (oy + p.y)/2);
			ox = p.x;
			oy = p.y;
		}
		
		p = sp.mPoints.get(size-1);
		path.lineTo(p.x, p.y);
		
		return path;
	}
	public List<PathAndPaint> transfer() {
		List<PathAndPaint> pps = new ArrayList<PathAndPaint>();
//		Log.i(TAG, "mSerPaths.size() = " + mSerPaths.size());
		for (SerPath sp : mSerPaths) {
			Paint paint = transferPaint(sp);
			Path path = transferPath(sp);
			pps.add(new PathAndPaint(path, paint));
		}
		return pps;
	}

	//-加载、保存、清空轨迹------------------------------
	private static String mSavePath = "/sdcard/.pathinfo";
	public static PathInfo load() {
		PathInfo pi = null;
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(new FileInputStream(mSavePath));
			pi = (PathInfo)ois.readObject();
			Log.i(TAG, "load ok, size = " + pi.mSerPaths.size());
		} catch (StreamCorruptedException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			if (ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				ois = null;
			}
			if (pi == null) {
				pi = new PathInfo();
			}
		}
		return pi;
	}
	
	public void save() {
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(new FileOutputStream(mSavePath));
			oos.writeObject(this);
			Log.i(TAG, "save ok, size = " + mSerPaths.size());
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (oos != null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				oos = null;
			}	
		}
	}
	
	public void clean() {
		File f = new File(mSavePath);
		if (f.exists()) {
			f.delete();
		}
		mSerPaths = new ArrayList<PathInfo.SerPath>();
	}
}

package org.ckl.path;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class SavePathActivity extends Activity {
	private PathInfo mPathInfo;
	private MyView mMyView;
	private Button mClean, mBack;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mPathInfo = PathInfo.load();
        
        mMyView = (MyView)findViewById(R.id.myview);
        mMyView.setPathInfo(mPathInfo);
        
        mClean = (Button)findViewById(R.id.clean);
        mClean.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				mPathInfo.clean();
				mMyView.setPathInfo(mPathInfo);
			}
		});
        
        mBack = (Button)findViewById(R.id.back);
        mBack.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				SavePathActivity.this.finish();
			}
		});
    }
    
    protected void onDestroy() {
    	if (mPathInfo != null) {
    		mPathInfo.save();
    		mPathInfo = null;
    	}
    	super.onDestroy();
    }
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"> 
	    <TextView
	        android:layout_weight="1"
	        android:layout_width="0dip"
	        android:layout_height="wrap_content"
	        android:text="@string/hello" />
	    <Button 
	        android:id="@+id/clean"
	        android:text="clean"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"/>
	    <Button 
	        android:id="@+id/back"
	        android:text="back"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"/>
    </LinearLayout>
	<org.ckl.path.MyView
	    android:id="@+id/myview"
	    android:layout_width="fill_parent"
	    android:layout_height="fill_parent"
	    android:src="@drawable/mj"
	    android:background="@android:color/white"/>
</LinearLayout>



【上篇】
【下篇】

抱歉!评论已关闭.