模仿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可以点击打开下载链接