簡單筆畫軌跡的繪製,並通過儲存軌跡點,實現Path的儲存和恢複。

來源:互聯網
上載者:User

儲存畫板中繪製的軌跡,有兩種方法:

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>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.