图片编辑,涂鸦。仿qq截图

模仿qq截图,并对截图后的图片进行编辑自己做了一个可以从相机,相册中获取图片并对图片进行编辑的功能模块。

这个是效果图。

下面直接上代码。


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

import com.example.editpicture.R;

/**
 * 对图片进行编辑的activity
 * 
 * @author yyw
 * 
 */
public class DrawAct extends Activity implements Callback, OnClickListener, OnCheckedChangeListener, OnSeekBarChangeListener {
	public static final String PIC_ACTION = "action";
	public static final String PIC_PATH = "file_uri";
	private static final String TAG = "MainActivity";
	private Button btnCancle, btnSava, btnBack;
	private RadioGroup group, colorGroup;
	private CameraSurfaceView surfaceView;
	private File files;
	private SeekBar skWordSize;
	private Bitmap bitmap;
	private TextView tvSize;

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (2235 == requestCode && resultCode == Activity.RESULT_OK) { // 相册获取照片
			// 把照片复制到指定的文件下
			if (data != null) {
				Uri uri = data.getData();
				String sourceFilePath = getPath(uri);
				if (files != null) {
					copyFile(sourceFilePath, files.getPath());
				} else {
					finish();
				}
			}
		} else if (requestCode == 2234 && resultCode == Activity.RESULT_OK) {
		} else {
			finish();
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	/**
	 * 将文件复制到指定位置上
	 * 
	 * @param fromFilePath
	 *            文件的原路径
	 * @param toFilePath
	 *            文件的目标路径
	 * @return Boolean true文件复制完成,false文件复制操作失败
	 * */
	public static Boolean copyFile(String fromFilePath, String toFilePath) {
		FileInputStream fis = null;
		FileOutputStream fos = null;

		try {
			fis = new FileInputStream(fromFilePath);
			fos = new FileOutputStream(toFilePath);

			byte[] buff = new byte[1024];
			while (fis.read(buff) > 0) {
				fos.write(buff);
			}

			fis.close();
			fos.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} finally {

		}
		return true;
	}

	/**
	 * 获取图片的地址
	 * 
	 * @param uri
	 * @return
	 */
	private String getPath(Uri uri) {
		String[] projection = { MediaStore.Images.Media.DATA };
		Cursor cursor = managedQuery(uri, projection, null, null, null);
		int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
		cursor.moveToFirst();
		String path = cursor.getString(column_index);
		cursor.close();
		return path;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.i(TAG, "onCreate");
		setContentView(R.layout.demo);
		btnCancle = (Button) findViewById(R.id.cancle);
		group = (RadioGroup) findViewById(R.id.group);
		btnSava = (Button) findViewById(R.id.sava);
		colorGroup = (RadioGroup) findViewById(R.id.color);
		skWordSize = (SeekBar) findViewById(R.id.sk_word_size);
		surfaceView = (CameraSurfaceView) findViewById(R.id.sv);
		tvSize = (TextView) findViewById(R.id.tv_size);
		btnBack = (Button) findViewById(R.id.back);
		surfaceView.getHolder().addCallback(this);
		btnCancle.setOnClickListener(this);
		btnSava.setOnClickListener(this);
		btnBack.setOnClickListener(this);
		group.setOnCheckedChangeListener(this);
		colorGroup.setOnCheckedChangeListener(this);
		skWordSize.setMax(46);
		skWordSize.setProgress(16);
		skWordSize.setOnSeekBarChangeListener(this);
		getCamera();
		selectColor(colorGroup.getCheckedRadioButtonId());

	}

	/**
	 * 打开相册或者相机
	 */
	private void getCamera() {
		Intent data = getIntent();
		String action = data.getStringExtra(PIC_ACTION);
		String file = data.getStringExtra(PIC_PATH);
		files = new File(file);
		if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)) {
			Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
			intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(files));
			startActivityForResult(intent, 2234);
		} else if (Intent.ACTION_PICK.equals(action)) {
			Intent intent = new Intent(Intent.ACTION_PICK);
			intent.setType("image/*");
			startActivityForResult(intent, 2235);
		}
	}

	public void onClick(View v) {
		Log.i(TAG, "onClick");
		switch (v.getId()) {
		case R.id.sava:
			Bitmap bitmap = surfaceView.getmBitmap();
			if (bitmap != null) {
				savaToSd(bitmap);
			}
			setResult(RESULT_OK);
			finish();
			break;
		case R.id.cancle:
			surfaceView.back();
			break;
		case R.id.back:
			finish();
			break;
		default:
			break;
		}
	}

	/**
	 * 把图片保存到sd卡
	 * 
	 * @param bitmap
	 */
	private void savaToSd(Bitmap bitmap) {
		if (files == null) {
			return;
		}
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(files);
			fos.write(baos.toByteArray());
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		surfaceView.setCanDraw(true);
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		Log.i(TAG, "surfaceChanged");
		if (bitmap == null) {
			bitmap = getZoomBmpByDecodePath(files.getAbsolutePath(), width, height).copy(Bitmap.Config.ARGB_8888, true);
			LayoutParams layoutParams = surfaceView.getLayoutParams();
			layoutParams.height = bitmap.getHeight();
			layoutParams.width = bitmap.getWidth();
			surfaceView.setLayoutParams(layoutParams);
			Log.i(TAG, "bitmap: " + bitmap.getWidth() + "-" + bitmap.getHeight());
			Log.i(TAG, "sv: " + width + "-" + height);
			surfaceView.setmBitmap(bitmap);
			surfaceView.setCanDraw(true);
		}
	}

	public Bitmap getZoomBmpByDecodePath(String path, int w, int h) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(path, options);
		options.inSampleSize = calculateInSampleSize(options, w, h);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(path, options);
	}

	/**
	 * 计算缩略图压缩的比列,因为每张图片长宽不一样,压缩比列也不一样
	 * 
	 * @param options
	 * @param reqWidth
	 * @param reqHeight
	 * @return
	 */
	public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;
		if (height > reqHeight || width > reqWidth) {
			if (width > height) {
				inSampleSize = Math.round((float) height / (float) reqHeight);
			} else {
				inSampleSize = Math.round((float) width / (float) reqWidth);
			}
		}
		return inSampleSize;
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {

	}

	@Override
	public void onCheckedChanged(RadioGroup group, int checkedId) {
		if (group.equals(this.group)) {
			selectPath(checkedId);
		} else if (group.equals(colorGroup)) {
			selectColor(checkedId);
		}

	}

	/**
	 * 选择图形
	 * 
	 * @param checkedId
	 */
	private void selectPath(int checkedId) {
		switch (checkedId) {
		case R.id.word:
			surfaceView.setCurrentDraw(CameraSurfaceView.DRAW_WORD);
			break;
		case R.id.line:
			surfaceView.setCurrentDraw(CameraSurfaceView.DRAW_PATH);
			break;
		case R.id.rect:
			surfaceView.setCurrentDraw(CameraSurfaceView.DRAW_RECT);
			break;
		case R.id.circle:
			surfaceView.setCurrentDraw(CameraSurfaceView.DRAW_CIRCLE);
			break;
		case R.id.arrow:
			surfaceView.setCurrentDraw(CameraSurfaceView.DRAW_ARROW);
			break;
		case R.id.oval:
			surfaceView.setCurrentDraw(CameraSurfaceView.DRAW_OVAL);
			break;
		case R.id.nothing:
			surfaceView.setCurrentDraw(CameraSurfaceView.DRAW_NOTHING);
			break;
		default:
			break;
		}
	}

	/**
	 * 选择画笔颜色
	 * 
	 * @param checkedId
	 */
	private void selectColor(int checkedId) {
		switch (checkedId) {
		case R.id.green:
			surfaceView.setColor(Color.GREEN);
			changeOtherColor(Color.GREEN);
			break;
		case R.id.blue:
			surfaceView.setColor(Color.BLUE);
			changeOtherColor(Color.BLUE);
			break;
		case R.id.yellow:
			surfaceView.setColor(Color.YELLOW);
			changeOtherColor(Color.YELLOW);
			break;
		case R.id.red:
			surfaceView.setColor(Color.RED);
			changeOtherColor(Color.RED);
			break;
		case R.id.black:
			surfaceView.setColor(Color.BLACK);
			changeOtherColor(Color.BLACK);
			break;
		case R.id.white:
			surfaceView.setColor(Color.WHITE);
			changeOtherColor(Color.WHITE);
			break;
		default:
			changeOtherColor(Color.BLACK);
			break;
		}
	}

	private void changeOtherColor(int color) {
		tvSize.setTextColor(color);
		for (int i = 0; i < group.getChildCount(); i++) {
			if (group.getChildAt(i) instanceof TextView) {
				TextView tvChild = (TextView) group.getChildAt(i);
				tvChild.setTextColor(color);
			}
		}
	}

	@Override
	public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
		if (fromUser) {// 选择字体大小
			surfaceView.setTextSize(progress + 8);
			tvSize.setText(String.valueOf(progress + 8));
		}
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {

	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {

	}

	@Override
	protected void onDestroy() {
		if (bitmap != null) {
			bitmap.recycle();
			bitmap = null;
		}
		super.onDestroy();
	}
}


 
 上面的代码是Activity的类用来获取图片,设置编辑图片的参数。 

CameraSurfaceView是自定义的画图的类。

package com.example.camera;

import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.view.animation.ScaleAnimation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.PopupWindow;

import com.example.editpicture.R;

/**
 * 显示图片并且画图的View
 * 
 * @author yyw
 * 
 */
public class CameraSurfaceView extends SurfaceView implements Runnable {
	private static final String TAG = "CameraSurfaceView";
	public static final int DRAW_NOTHING = 0x00;
	public static final int DRAW_PATH = 0X01;
	public static final int DRAW_WORD = 0x02;
	public static final int DRAW_RECT = 0x03;
	public static final int DRAW_CIRCLE = 0x04;
	public static final int DRAW_OVAL = 0x05;
	public static final int DRAW_ARROW = 0X06;
	public static final float MAX_SCALE = 4;// 最大的放缩比例
	public static final float MIN_SCALE = 1;// 最小的放缩比例
	private int currentDraw = DRAW_NOTHING;
	private Paint paint;
	private Bitmap mBitmap;
	private Canvas mCanvas;
	private ArrayList<Word> words = new ArrayList<Word>();
	private ArrayList<CirclePath> circlePaths = new ArrayList<CirclePath>();
	private ArrayList<RectPath> rectPaths = new ArrayList<RectPath>();
	private ArrayList<OvalPath> ovalPaths = new ArrayList<OvalPath>();
	private ArrayList<ArrowPath> arrowPaths = new ArrayList<ArrowPath>();
	private ArrayList<LinePath> linePaths = new ArrayList<LinePath>();
	private boolean canDraw;
	private PopupWindow popupWindow;
	private LinePath currentLinPath;
	private CirclePath currentCirclePath;
	private RectPath currentRectPath;
	private OvalPath currentOvalPath;
	private ArrowPath currentArrowPath;
	private Path mPath;
	private Matrix matrix = new Matrix();
	private GestureDetector detector;

	public CameraSurfaceView(Context context) {
		super(context);
		init(context);
	}

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

	public CameraSurfaceView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	private void init(Context context) {
		paint = new Paint();
		paint.setColor(Color.RED);
		paint.setStrokeWidth(2);
		paint.setStyle(Style.STROKE);
		paint.setTextSize(25);
		paint.setAntiAlias(true);
		detector = new GestureDetector(listener);
	}

	private SimpleOnGestureListener listener = new SimpleOnGestureListener() {
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
			float[] value = new float[9];
			matrix.getValues(value);
			float maxTranX = mBitmap.getWidth() * value[Matrix.MSCALE_X] - getWidth();
			float maxTranY = mBitmap.getHeight() * value[Matrix.MSCALE_X] - getHeight();
			if (value[Matrix.MSCALE_X] >= MIN_SCALE) {
				float dx = -distanceX + value[Matrix.MTRANS_X];//计算出实际会偏移的量
				float dy = -distanceY + value[Matrix.MTRANS_Y];
				if (dx > 0) {//如果实际量超出边框就就把相对偏移量为零
					dx = 0;
				} else if (-dx > maxTranX) {
					dx = 0;
				} else {
					dx = -distanceX;
				}
				if (dy > 0) {
					dy = 0;
				} else if (-dy > maxTranY) {
					dy = 0;
				} else {
					dy = -distanceY;
				}
				matrix.postTranslate(dx, dy);
				Log.i(TAG, "onScroll" + dx + ":" + dy + "mBitmap.getHeight()" + mBitmap.getHeight() + "value[Matrix.MSCALE_X]" + value[Matrix.MSCALE_X]);
				post(CameraSurfaceView.this);
				return true;
			}
			return false;
		}

		public boolean onDoubleTap(MotionEvent e) {
			Log.i(TAG, "onDoubleTap");
			float[] value = new float[9];
			matrix.getValues(value);
			if (value[Matrix.MSCALE_X] > MIN_SCALE) {
				matrix.reset();
			} else {
				float px = e.getX();
				float py = e.getY();
				float sx = MAX_SCALE / value[Matrix.MSCALE_X];
				float sy = MAX_SCALE / value[Matrix.MSCALE_Y];
				matrix.postScale(sx, sy, px, py);
			}
			post(CameraSurfaceView.this);
			return true;
		}
	};
	private float mOldDist = 0;

	@SuppressLint("ClickableViewAccessibility")
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (canDraw) {
			switch (currentDraw) {
			case DRAW_PATH:
				lineEvevn(event);
				break;
			case DRAW_WORD:
				wordEven(event);
				break;
			case DRAW_CIRCLE:
				circleEvent(event);
				break;
			case DRAW_RECT:
				rectEvent(event);
				break;
			case DRAW_ARROW:
				arrowEvent(event);
				break;
			case DRAW_OVAL:
				ovalEvent(event);
				break;
			case DRAW_NOTHING:
				if (!nothingEvent(event)) {
					detector.onTouchEvent(event);
				}
				break;
			default:
				break;
			}
			return true;
		}

		return super.onTouchEvent(event);
	}

	/**
	 * 缩放处理
	 * 
	 * @param event
	 * @return
	 */
	private boolean nothingEvent(MotionEvent event) {
		int count = event.getPointerCount();
		if (count > 1) {
			int action = event.getAction();
			action = action & MotionEvent.ACTION_MASK;
			switch (action) {
			case MotionEvent.ACTION_POINTER_DOWN:
				Log.i(TAG, "ACTION_DOWN");
				mOldDist = getDistOfTowPoints(event);
				break;
			case MotionEvent.ACTION_MOVE:
				Log.i(TAG, "ACTION_MOVE");
				float mNewDist = getDistOfTowPoints(event);
				if (Math.abs(mNewDist - mOldDist) > 50) {
					float[] value = new float[9];
					matrix.getValues(value);
					Log.i(TAG, "偏移量" + value[Matrix.MTRANS_X] + ":" + value[Matrix.MTRANS_Y]);
					float scale = value[Matrix.MSCALE_X];//原来的放缩量
					float px = (event.getX(0) + event.getX(1)) / 2;
					float py = (event.getY(0) + event.getY(1)) / 2;
					if (mOldDist > mNewDist) {
						scale -= Math.abs(mNewDist - mOldDist) / 500f;//计算现在的放缩量
						// Log.i(TAG, "缩小" + scale + ":" + Math.abs(mNewDist -
						// mOldDist));
					} else {
						scale += Math.abs(mNewDist - mOldDist) / 500f;//计算现在的放缩量
						// Log.i(TAG, "放大" + scale);
					}
					if (scale < MIN_SCALE) {//如果放缩量小于最低的就置为最低放缩比
						scale = MIN_SCALE;

					} else if (scale > MAX_SCALE) {//如果放缩量大于最高的就置为最高放缩比
						scale = MAX_SCALE;
					}
					if (scale == MIN_SCALE) {//如果放缩量为最小就把矩阵重置
						matrix.reset();
					} else {
						scale = scale / value[Matrix.MSCALE_X];//计算出相对的放缩量,使矩阵的放缩量为放缩到计算出来的放缩量。
						matrix.postScale(scale, scale, px, py);
					}
					Log.i(TAG, "" + scale / value[Matrix.MSCALE_X] + ":" + Math.abs(mNewDist - mOldDist));
					mOldDist = mNewDist;
					post(this);
				}
				break;
			default:
				break;
			}
			return true;
		}
		return false;
	}

	/**
	 * 获取两点之间的距离
	 * 
	 * @param p1
	 * @param p2
	 * @return int 返回两点间的距离
	 * */
	private float getDistOfTowPoints(MotionEvent event) {
		float x0 = event.getX(0);
		float y0 = event.getY(0);
		float x1 = event.getX(1);
		float y1 = event.getY(1);
		float lengthX = Math.abs(x0 - x1);
		float lengthY = Math.abs(y0 - y1);
		return (float) Math.sqrt(lengthX * lengthX + lengthY * lengthY);
	}

	/**
	 * 当画椭圆时
	 * 
	 * @param event
	 */
	private void ovalEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Paint cPaint = new Paint(paint);
			RectF rectF = new RectF(event.getX(), event.getY(), event.getX() + 1, event.getY() + 1);
			currentOvalPath = new OvalPath(rectF, cPaint);
			break;
		case MotionEvent.ACTION_MOVE:
			float mX = event.getX();
			float mY = event.getY();
			currentOvalPath.getRectF().right = mX;
			currentOvalPath.getRectF().bottom = mY;
			break;
		case MotionEvent.ACTION_UP:
			float uX = event.getX();
			float uY = event.getY();
			currentOvalPath.getRectF().right = uX;
			currentOvalPath.getRectF().bottom = uY;
			currentOvalPath.reset(matrix);
			ovalPaths.add(currentOvalPath);
			currentOvalPath = null;
			break;
		default:
			break;
		}
		post(this);

	}

	/**
	 * 当画箭头
	 * 
	 * @param event
	 */
	private void arrowEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Paint cPaint = new Paint(paint);
			currentArrowPath = new ArrowPath((int) event.getX(), (int) event.getY(), (int) event.getX() + 1, (int) event.getY() + 1, cPaint);
			break;
		case MotionEvent.ACTION_MOVE:
			float mX = event.getX();
			float mY = event.getY();
			currentArrowPath.seteX((int) mX);
			currentArrowPath.seteY((int) mY);
			break;
		case MotionEvent.ACTION_UP:
			float uX = event.getX();
			float uY = event.getY();
			currentArrowPath.seteX((int) uX);
			currentArrowPath.seteY((int) uY);
			currentArrowPath.reset(matrix);
			arrowPaths.add(currentArrowPath);
			currentArrowPath = null;
			break;
		default:
			break;
		}
		post(this);
	}

	/**
	 * 画方
	 * 
	 * @param event
	 */
	private void rectEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			currentRectPath = new RectPath();
			Paint cPaint = new Paint(paint);
			currentRectPath.setPaint(cPaint);
			currentRectPath.setLeft(event.getX());
			currentRectPath.setTop(event.getY());
			currentRectPath.setRight(event.getX() + 1);
			currentRectPath.setBottom(event.getY() + 1);
			break;
		case MotionEvent.ACTION_MOVE:
			float mX = event.getX();
			float mY = event.getY();
			currentRectPath.setRight(mX);
			currentRectPath.setBottom(mY);
			break;
		case MotionEvent.ACTION_UP:
			float uX = event.getX();
			float uY = event.getY();
			currentRectPath.setRight(uX);
			currentRectPath.setBottom(uY);
			currentRectPath.reset(matrix);
			rectPaths.add(currentRectPath);
			currentRectPath = null;
			break;
		default:
			break;
		}
		post(this);
	}

	/**
	 * 画圆
	 * 
	 * @param event
	 */
	private void circleEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			currentCirclePath = new CirclePath();
			currentCirclePath.setCx(event.getX());
			currentCirclePath.setCy(event.getY());
			currentCirclePath.setRadius(1);
			Paint cPaint = new Paint(paint);
			currentCirclePath.setPaint(cPaint);
			break;
		case MotionEvent.ACTION_MOVE:
			float mX = event.getX();
			float mY = event.getY();
			float r = (float) Math.sqrt(Math.pow(Math.abs(mX - currentCirclePath.getCx()), 2) + Math.pow(Math.abs(mY - currentCirclePath.getCy()), 2));
			currentCirclePath.setRadius(r);
			break;
		case MotionEvent.ACTION_UP:
			float uX = event.getX();
			float uY = event.getY();
			float ur = (float) Math.sqrt(Math.pow(Math.abs(uX - currentCirclePath.getCx()), 2) + Math.pow(Math.abs(uY - currentCirclePath.getCy()), 2));
			currentCirclePath.setRadius(ur);
			currentCirclePath.reset(matrix);
			circlePaths.add(currentCirclePath);
			currentCirclePath = null;
			break;
		default:
			break;
		}
		post(this);
	}

	/**
	 * 写字
	 * 
	 * @param event
	 */
	private void wordEven(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.i(TAG, "DRAW_WORD+ACTION_DOWN");
			showPop((int) event.getX(), (int) event.getY());
			break;
		default:
			break;
		}
	}

	/**
	 * 划线
	 * 
	 * @param event
	 */
	private void lineEvevn(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mPath = new Path();
			currentLinPath = new LinePath(new Path(), new Paint(paint));
			currentLinPath.getPath().moveTo(event.getX(), event.getY());
			pathTo(event);
			break;
		case MotionEvent.ACTION_MOVE:
			currentLinPath.getPath().lineTo(event.getX(), event.getY());
			pathTo(event);
			break;
		case MotionEvent.ACTION_UP:
			pathTo(event);
			currentLinPath.setPath(mPath);
			linePaths.add(currentLinPath);
			currentLinPath = null;
			mPath = null;
			break;
		default:
			break;
		}
		post(this);
	}

	private void pathTo(MotionEvent event) {
		Point pointD = new Point((int) event.getX(), (int) event.getY());
		calculationRealPoint(pointD, matrix);
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			mPath.moveTo(pointD.x, pointD.y);
		} else {
			mPath.lineTo(pointD.x, pointD.y);
		}
	}

	public void calculationRealPoint(Point point, Matrix matrix) {
		float[] values = new float[9];
		matrix.getValues(values);
		int sX = point.x;
		int sY = point.y;
		point.x = (int) ((sX - values[Matrix.MTRANS_X]) / values[Matrix.MSCALE_X]);
		point.y = (int) ((sY - values[Matrix.MTRANS_Y]) / values[Matrix.MSCALE_Y]);
	}

	/**
	 * 显示popupWindow输入文字
	 * 
	 * @param x
	 * @param y
	 */
	private void showPop(final float x, final float y) {
		if (popupWindow != null && popupWindow.isShowing()) {
			popupWindow.dismiss();
		}
		View contentView = View.inflate(getContext(), R.layout.popupwindow, null);
		final EditText etWord = (EditText) contentView.findViewById(R.id.et_word);
		etWord.setInputType(InputType.TYPE_CLASS_TEXT);
		Button btnOk = (Button) contentView.findViewById(R.id.btn_ok);
		btnOk.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				String word = etWord.getText().toString().trim();
				if (!TextUtils.isEmpty(word)) {
					Paint key = new Paint(paint);
					key.setStrokeWidth(1);
					key.setTypeface(Typeface.DEFAULT);
					key.setStyle(Style.FILL);
					Word wor = new Word(x, y, key, word);
					wor.reset(matrix);
					words.add(wor);

					post(CameraSurfaceView.this);
				}
				if (popupWindow != null && popupWindow.isShowing()) {
					popupWindow.dismiss();
				}
			}
		});
		popupWindow = new PopupWindow(contentView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
		popupWindow.setFocusable(true);
		popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));// PopupWindow没有背景色,必须设置背景色
		popupWindow.showAtLocation(this, Gravity.TOP + Gravity.LEFT, (int) x + getLeft(), (int) y + getTop());
		ScaleAnimation animation = new ScaleAnimation(0.2f, 1.2f, 0.2f, 1.2f, 0.5f, 0.5f);
		animation.setDuration(100);
		// animation.setFillAfter(true);
		contentView.startAnimation(animation);
	}

	@Override
	public void run() {
		if (mBitmap != null) {
			SurfaceHolder surfaceHolder = getHolder();
			Canvas canvas = surfaceHolder.lockCanvas();
			canvas.drawColor(Color.BLACK);
			canvas.save();
			canvas.setMatrix(matrix);
			canvas.drawBitmap(mBitmap, 0, 0, paint);
			drawText(canvas, words);
			drawOval(canvas, ovalPaths);
			drawArrow(canvas, arrowPaths);
			drawCircle(canvas, circlePaths);
			drawRect(canvas, rectPaths);
			drawLine(canvas, linePaths);
			// canvas.save();
			canvas.restore();
			drawCurrent(canvas);
			surfaceHolder.unlockCanvasAndPost(canvas);
		}

	}

	private void drawLine(Canvas canvas, ArrayList<LinePath> linePaths2) {
		for (LinePath linePath : linePaths2) {
			canvas.drawPath(linePath.getPath(), linePath.getPaint());
		}

	}

	private void drawArrow(Canvas canvas, ArrayList<ArrowPath> arrowPaths2) {
		for (ArrowPath arrowPath : arrowPaths2) {
			drawAL(arrowPath.getsX(), arrowPath.getsY(), arrowPath.geteX(), arrowPath.geteY(), canvas, arrowPath.getPaint());
		}

	}

	private void drawOval(Canvas canvas, ArrayList<OvalPath> ovalPaths2) {
		for (OvalPath ovalPath : ovalPaths2) {
			canvas.drawOval(ovalPath.getRectF(), ovalPath.getPaint());
		}

	}

	private void drawRect(Canvas mCanvas2, ArrayList<RectPath> rectPaths2) {
		for (RectPath rectPath : rectPaths2) {
			mCanvas2.drawRect(rectPath.getLeft(), rectPath.getTop(), rectPath.getRight(), rectPath.getBottom(), rectPath.getPaint());
		}

	}

	private void drawCircle(Canvas mCanvas2, ArrayList<CirclePath> circlePaths2) {
		for (CirclePath circlePath : circlePaths2) {
			mCanvas2.drawCircle(circlePath.getCx(), circlePath.getCy(), circlePath.getRadius(), circlePath.getPaint());

		}

	}

	private void drawText(Canvas mCanvas2, ArrayList<Word> words2) {
		for (Word word : words2) {
			mCanvas2.drawText(word.getWordString(), word.getLeft(), word.getTop(), word.getPaint());
		}

	}

	/**
	 * 画当前的图形
	 * 
	 * @param canvas
	 */
	private void drawCurrent(Canvas canvas) {
		switch (currentDraw) {
		case DRAW_CIRCLE:
			if (currentCirclePath != null) {

				canvas.drawCircle(currentCirclePath.getCx(), currentCirclePath.getCy(), currentCirclePath.getRadius(), currentCirclePath.getPaint());
			}
			break;
		case DRAW_RECT:
			if (currentRectPath != null) {
				canvas.drawRect(currentRectPath.getLeft(), currentRectPath.getTop(), currentRectPath.getRight(), currentRectPath.getBottom(), currentRectPath.getPaint());
			}
			break;
		case DRAW_ARROW:
			if (currentArrowPath != null) {
				drawAL(currentArrowPath.getsX(), currentArrowPath.getsY(), currentArrowPath.geteX(), currentArrowPath.geteY(), canvas, currentArrowPath.getPaint());
			}
			break;
		case DRAW_OVAL:
			if (currentOvalPath != null) {
				canvas.drawOval(currentOvalPath.getRectF(), currentOvalPath.getPaint());
			}
		case DRAW_PATH:
			if (currentLinPath != null) {
				canvas.drawPath(currentLinPath.getPath(), currentLinPath.getPaint());
			}
			break;
		default:
			break;
		}
	}

	/**
	 * 画箭头
	 * 
	 * @param sx
	 * @param sy
	 * @param ex
	 * @param ey
	 */
	public void drawAL(int sx, int sy, int ex, int ey, Canvas myCanvas, Paint myPaint) {
		double H = 8; // 箭头高度
		double L = 3.5; // 底边的一半
		int x3 = 0;
		int y3 = 0;
		int x4 = 0;
		int y4 = 0;
		double awrad = Math.atan(L / H); // 箭头角度
		double arraow_len = Math.sqrt(L * L + H * H); // 箭头的长度
		double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len);
		double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len);
		Double X3 = ex - arrXY_1[0]; // (x3,y3)是第一端点
		x3 = X3.intValue();
		Double Y3 = ey - arrXY_1[1];
		y3 = Y3.intValue();
		Double X4 = ex - arrXY_2[0]; // (x4,y4)是第二端点
		x4 = X4.intValue();
		Double Y4 = ey - arrXY_2[1];
		y4 = Y4.intValue();
		// 画线
		myCanvas.drawLine(sx, sy, ex, ey, myPaint);
		Path triangle = new Path();
		triangle.moveTo(ex, ey);
		triangle.lineTo(x3, y3);
		triangle.lineTo(x4, y4);
		triangle.close();
		myCanvas.drawPath(triangle, myPaint);

	}

	/**
	 * 矢量旋转函数,求出与结束定点的x,y距离
	 * 
	 * @param px
	 *            x分量
	 * @param py
	 *            y分量
	 * @param ang
	 *            旋转角度
	 * @param isChLen
	 *            是否改变长度
	 * @param newLen
	 *            新长度
	 * @return
	 */
	public double[] rotateVec(int px, int py, double ang, boolean isChLen, double newLen) {

		double mathstr[] = new double[2];
		// double len = Math.sqrt(px*px + py*py);
		// double a = Math.acos(px/len);
		// double vx = Math.cos(a+ang)*len
		// double vy = Math.sin(a+ang)*len
		double vx = px * Math.cos(ang) - py * Math.sin(ang);
		double vy = px * Math.sin(ang) + py * Math.cos(ang);
		if (isChLen) {
			double d = Math.sqrt(vx * vx + vy * vy);
			vx = vx / d * newLen;
			vy = vy / d * newLen;
			mathstr[0] = vx;
			mathstr[1] = vy;
		}
		return mathstr;
	}

	public int getCurrentDraw() {
		return currentDraw;
	}

	public void setCurrentDraw(int currentDraw) {
		this.currentDraw = currentDraw;
		if (popupWindow != null && popupWindow.isShowing()) {
			popupWindow.dismiss();
		}
	}

	/**
	 * 返回一个画完的图片
	 * 
	 * @return
	 */
	public Bitmap getmBitmap() {
		mCanvas = new Canvas(mBitmap);
		drawText(mCanvas, words);
		drawCircle(mCanvas, circlePaths);
		drawRect(mCanvas, rectPaths);
		drawArrow(mCanvas, arrowPaths);
		drawOval(mCanvas, ovalPaths);
		drawLine(mCanvas, linePaths);
		return mBitmap;
	}

	public void setmBitmap(Bitmap mBitmap) {
		this.mBitmap = mBitmap;
		// mCanvas = new Canvas(this.mBitmap);
		// reset();
		post(this);
	}

	//
	// public void reset() {
	// if (bitmap != null) {
	// bitmap.recycle();
	// }
	// bitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),
	// mBitmap.getWidth());
	// dCanvas = new Canvas(bitmap);
	// }

	public boolean isCanDraw() {
		return canDraw;
	}

	public void setCanDraw(boolean canDraw) {
		this.canDraw = canDraw;
	}

	/**
	 * 清除对应的类型的最新的一个图形
	 */
	public void back() {
		switch (currentDraw) {
		case DRAW_CIRCLE:
			if (circlePaths.size() - 1 >= 0) {
				circlePaths.remove(circlePaths.size() - 1);
			}
			break;
		case DRAW_RECT:
			if (rectPaths.size() - 1 >= 0) {
				rectPaths.remove(rectPaths.size() - 1);
			}
			break;
		case DRAW_WORD:
			if (words.size() - 1 >= 0) {
				words.remove(words.size() - 1);
			}
			break;
		case DRAW_PATH:
			if (linePaths.size() - 1 >= 0) {
				linePaths.remove(linePaths.size() - 1);
			}
			break;
		case DRAW_ARROW:
			if (arrowPaths.size() - 1 >= 0) {
				arrowPaths.remove(arrowPaths.size() - 1);
			}
			break;
		case DRAW_OVAL:
			if (ovalPaths.size() - 1 >= 0) {
				ovalPaths.remove(ovalPaths.size() - 1);
			}
			break;
		case DRAW_NOTHING:
			AlertDialog.Builder builder = new Builder(getContext());
			builder.setTitle("清除");
			builder.setMessage("是否要清除全部内容?");
			builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
					words.clear();
					ovalPaths.clear();
					linePaths.clear();
					arrowPaths.clear();
					rectPaths.clear();
					circlePaths.clear();

				}
			}).setPositiveButton("取消", new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
				}
			}).show();
			break;
		default:
			break;
		}
		post(this);
	}

	public void setTextSize(float textSize) {
		paint.setTextSize(textSize);
	}

	public void setColor(int color) {
		paint.setColor(color);
	}

}

最近学了一些新的东西添加到这上面:

1,双击缩放的平滑动画效果:

 public boolean onDoubleTap(MotionEvent e) {
            float[] value = new float[9];
            mMatrix.getValues(value);
            if (value[Matrix.MSCALE_X] > MIN_SCALE) {
                if (Build.VERSION.SDK_INT <Build.VERSION_CODES.HONEYCOMB){
                    mMatrix.reset();
                    postInvalidate();
                }else {
                    float centerX = (getLeft()+getRight())/2;
                    float centerY = (getTop()+getBottom())/2;
                    startAnimator(value[Matrix.MSCALE_X],MIN_SCALE,centerX,centerY);
                }
            } else {
                float px = e.getX();
                float py = e.getY();
                if (Build.VERSION.SDK_INT <Build.VERSION_CODES.HONEYCOMB){
                    float sx = MAX_SCALE / value[Matrix.MSCALE_X];
                    float sy = MAX_SCALE / value[Matrix.MSCALE_Y];
                    mMatrix.postScale(sx, sy, px, py);
                    postInvalidate();
                }else {
                    float min = Math.min(value[Matrix.MSCALE_X],value[Matrix.MSCALE_Y]);
                    startAnimator(min,MAX_SCALE, px,py);
                }
            }
            return true;
        }
 @TargetApi(11)
    private void startAnimator(float start,float end,final float px,final float py){
        ObjectAnimator animator = ObjectAnimator.ofObject(this,"scale",new ScaleEvaluator(),start,end);
        animator.setDuration(200);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float curentScale = (Float) animation.getAnimatedValue();
                float[] value = new float[9];
                mMatrix.getValues(value);

                float sx = curentScale / value[Matrix.MSCALE_X];
                float sy = curentScale / value[Matrix.MSCALE_Y];
                mMatrix.postScale(sx, sy, px, py);
//				mMatrix.getValues(value);

                postInvalidate();
            }
        });
        animator.start();
    }
    @TargetApi(11)
    private static class ScaleEvaluator implements TypeEvaluator {
        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            float result = 1;
            try {
                result = fraction*((Float)endValue - (Float)startValue) + (Float)startValue;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    }
2:,缩放的边界的校验,在给 Canvas . setMatrix之前添加该方法

/**
     * 矫正放缩的比例
     * @param matrix
     */
    private void judgeMatrix(Matrix matrix) {
        float[] value = new float[9];
        matrix.getValues(value);
        final float xscale = value[Matrix.MSCALE_X];
        final float yscale = value[Matrix.MSCALE_Y];
        if (xscale <= MIN_SCALE || yscale <= MIN_SCALE) {//如果x,y方向上的放缩比小于最小值重置matrix
            matrix.reset();
        }else {
            final float transX = value[Matrix.MTRANS_X];
            final float transY = value[Matrix.MTRANS_Y];
            float dx = 0;
            float dy = 0;
            if (transX >= 0){//如果有向左平移量就要向右平移回来
                dx = -transX;
            }else {
                float width = (xscale - 1)* getWidth();
                if (Math.abs(transX) > width){//如果向右平移量大于View可以移动的宽度,就矫正为View可以移动的宽度
                    dx = Math.abs(transX) - width;
                }
            }
            if (transY >=0 ){//如果有向上平移量就要向下平移回来
                dy = -transY;
            }else {
                float heitht = (yscale - 1) * getHeight();
                if (Math.abs(transY) > heitht){//如果向右平移量大于View可以移动的高度,就矫正为View可以移动的高度
                    dy = Math.abs(transY) - heitht;
                }
            }
            matrix.postTranslate(dx,dy);
        }
    }


最主要的功能代码已经贴出来了,如果要Demo可以点击打开下载链接



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值