优化方式

增加触摸点个数

减少每次刷新的区域(每次只刷新一个小矩形区域)

不直接说了,直接上代码。

public class PaletteView extends View {

private Paint mPaint;

private Path mPath;

private float mLastX;

private float mLastY;

private Bitmap mBufferBitmap;

private Canvas mBufferCanvas;

private static final int MAX_CACHE_STEP = 20;

private List mDrawingList;

private List mRemovedList;

private Xfermode mXferModeClear;

private Xfermode mXferModeDraw;

private int mDrawSize;

private int mEraserSize;

private int mPenAlpha = 255;

private boolean mCanEraser;

private Callback mCallback;

public enum Mode {

DRAW,

ERASER

}

private Mode mMode = Mode.DRAW;

public PaletteView(Context context) {

super(context);

init();

}

public PaletteView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}

public PaletteView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

public interface Callback {

void onUndoRedoStatusChanged();

}

public void setCallback(Callback callback) {

mCallback = callback;

}

private void init() {

setDrawingCacheEnabled(true);

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setFilterBitmap(true);

mPaint.setStrokeJoin(Paint.Join.ROUND);

mPaint.setStrokeCap(Paint.Cap.ROUND);

mDrawSize = DimenUtils.dp2pxInt(3);

mEraserSize = DimenUtils.dp2pxInt(30);

mPaint.setStrokeWidth(mDrawSize);

mPaint.setColor(Color.BLACK);

mXferModeDraw = new PorterDuffXfermode(PorterDuff.Mode.SRC);

mXferModeClear = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);

mPaint.setXfermode(mXferModeDraw);

}

private void initBuffer() {

mBufferBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);

mBufferCanvas = new Canvas(mBufferBitmap);

}

private abstract static class DrawingInfo {

Paint paint;

abstract void draw(Canvas canvas);

}

private static class PathDrawingInfo extends DrawingInfo {

Path path;

@Override

void draw(Canvas canvas) {

canvas.drawPath(path, paint);

}

}

public Mode getMode() {

return mMode;

}

public void setMode(Mode mode) {

if (mode != mMode) {

mMode = mode;

if (mMode == Mode.DRAW) {

mPaint.setXfermode(mXferModeDraw);

mPaint.setStrokeWidth(mDrawSize);

} else {

mPaint.setXfermode(mXferModeClear);

mPaint.setStrokeWidth(mEraserSize);

}

}

}

public void setEraserSize(int size) {

mEraserSize = size;

}

public void setPenRawSize(int size) {

mDrawSize = size;

if (mMode == Mode.DRAW) {

mPaint.setStrokeWidth(mDrawSize);

}

}

public void setPenColor(int color) {

mPaint.setColor(color);

}

private void reDraw() {

if (mDrawingList != null) {

mBufferBitmap.eraseColor(Color.TRANSPARENT);

for (DrawingInfo drawingInfo : mDrawingList) {

drawingInfo.draw(mBufferCanvas);

}

invalidate();

}

}

public int getPenColor() {

return mPaint.getColor();

}

public int getPenSize() {

return mDrawSize;

}

public int getEraserSize() {

return mEraserSize;

}

public void setPenAlpha(int alpha) {

mPenAlpha = alpha;

if (mMode == Mode.DRAW) {

mPaint.setAlpha(alpha);

}

}

public int getPenAlpha() {

return mPenAlpha;

}

public boolean canRedo() {

return mRemovedList != null && mRemovedList.size() > 0;

}

public boolean canUndo() {

return mDrawingList != null && mDrawingList.size() > 0;

}

public void redo() {

int size = mRemovedList == null ? 0 : mRemovedList.size();

if (size > 0) {

DrawingInfo info = mRemovedList.remove(size - 1);

mDrawingList.add(info);

mCanEraser = true;

reDraw();

if (mCallback != null) {

mCallback.onUndoRedoStatusChanged();

}

}

}

public void undo() {

int size = mDrawingList == null ? 0 : mDrawingList.size();

if (size > 0) {

DrawingInfo info = mDrawingList.remove(size - 1);

if (mRemovedList == null) {

mRemovedList = new ArrayList<>(MAX_CACHE_STEP);

}

if (size == 1) {

mCanEraser = false;

}

mRemovedList.add(info);

reDraw();

if (mCallback != null) {

mCallback.onUndoRedoStatusChanged();

}

}

}

public void clear() {

if (mBufferBitmap != null) {

if (mDrawingList != null) {

mDrawingList.clear();

}

if (mRemovedList != null) {

mRemovedList.clear();

}

mCanEraser = false;

mBufferBitmap.eraseColor(Color.TRANSPARENT);

invalidate();

if (mCallback != null) {

mCallback.onUndoRedoStatusChanged();

}

}

}

public Bitmap buildBitmap() {

Bitmap bm = getDrawingCache();

Bitmap result = Bitmap.createBitmap(bm);

destroyDrawingCache();

return result;

}

private void saveDrawingPath() {

if (mDrawingList == null) {

mDrawingList = new ArrayList<>(MAX_CACHE_STEP);

} else if (mDrawingList.size() == MAX_CACHE_STEP) {

mDrawingList.remove(0);

}

Path cachePath = new Path(mPath);

Paint cachePaint = new Paint(mPaint);

PathDrawingInfo info = new PathDrawingInfo();

info.path = cachePath;

info.paint = cachePaint;

mDrawingList.add(info);

mCanEraser = true;

if (mCallback != null) {

mCallback.onUndoRedoStatusChanged();

}

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (mBufferBitmap != null) {

canvas.drawBitmap(mBufferBitmap, 0, 0, null);

}

}

@SuppressWarnings("all")

@Override

public boolean onTouchEvent(MotionEvent event) {

if (!isEnabled()) {

return false;

}

final int action = event.getAction() & MotionEvent.ACTION_MASK;

final float x = event.getX();

final float y = event.getY();

switch (action) {

case MotionEvent.ACTION_DOWN:

mLastX = x;

mLastY = y;

if (mPath == null) {

mPath = new Path();

}

mPath.moveTo(x, y);

break;

case MotionEvent.ACTION_MOVE:

if (mMode == Mode.DRAW) {

//橡皮擦模式,绘图模式

resetDirtyRect(x, y);

int historySize = event.getHistorySize();

for (int i = 0; i < historySize; i++) {

float historicalX = event.getHistoricalX(i);

float historicalY = event.getHistoricalY(i);

getDirtyRect(historicalX, historicalY);

mPath.lineTo(historicalX, historicalY);

}

mPath.lineTo(x, y);

if (mBufferBitmap == null) {

initBuffer();

}

mBufferCanvas.drawPath(mPath, mPaint);

invalidate((int) (mDirtyRect.left - HALF_STROKE_WIDTH),

(int) (mDirtyRect.top - HALF_STROKE_WIDTH),

(int) (mDirtyRect.right + HALF_STROKE_WIDTH),

(int) (mDirtyRect.bottom + HALF_STROKE_WIDTH));

} else {

//橡皮擦模式

//这里终点设为两点的中心点的目的在于使绘制的曲线更平滑,如果终点直接设置为x,y,效果和lineto是一样的,实际是折线效果

mPath.quadTo(mLastX, mLastY, (x + mLastX) / 2, (y + mLastY) / 2);

if (mBufferBitmap == null) {

initBuffer();

}

if (mMode == Mode.ERASER && !mCanEraser) {

break;

}

mBufferCanvas.drawPath(mPath, mPaint);

invalidate();

}

mLastX = x;

mLastY = y;

break;

case MotionEvent.ACTION_UP:

if (mMode == Mode.DRAW || mCanEraser) {

saveDrawingPath();

}

mPath.reset();

break;

}

return true;

}

private void resetDirtyRect(float eventX, float eventY) {

mDirtyRect.left = Math.min(mLastX, eventX);

mDirtyRect.right = Math.max(mLastX, eventX);

mDirtyRect.top = Math.min(mLastY, eventY);

mDirtyRect.bottom = Math.max(mLastY, eventY);

}

private void getDirtyRect(float historicalX, float historicalY) {

if (historicalX < mDirtyRect.left) {

mDirtyRect.left = historicalX;

} else if (historicalX > mDirtyRect.right) {

mDirtyRect.right = historicalX;

}

if (historicalY < mDirtyRect.top) {

mDirtyRect.top = historicalY;

} else if (historicalY > mDirtyRect.bottom) {

mDirtyRect.bottom = historicalY;

}

}

private static final float STROKE_WIDTH = 5f;

private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;

private final RectF mDirtyRect = new RectF();

}

使用方式

public class HandWritingFragment extends BaseFragment implements View.OnClickListener, PaletteView.Callback {

@BindView(R.id.mPaletteView)

PaletteView paletteView;

private ImageView mPenView, mClearView, mEraserView, mSaveView, mQuitView;

private ImageView blackPen, redPen, yellowPen, greenPen, pinkPen, purplePen;

private ProgressDialog progressDialog;

private UpLoadImagePresenter upLoadImagePresenter;

private HandWritePrestener handWritePrestener;

@Override

protected int getLayoutId() {

return R.layout.fragment_hand_writing;

}

@Override

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

upLoadImagePresenter = new UpLoadImagePresenter(getActivity(), handWriteView);

handWritePrestener = new HandWritePrestener(getActivity(), handWriteView);

View containerView = getActivity().getWindow().getDecorView().findViewById(R.id.task_info_container);

Bitmap bitmap = Bitmap.createBitmap(containerView.getWidth(), containerView.getHeight(), Bitmap.Config.ARGB_8888);

Canvas canvas = new Canvas(bitmap);

canvas.drawColor(Color.WHITE);

containerView.draw(canvas);

// paletteView.setBackgroundColor(Color.WHITE);

paletteView.setBackground(new BitmapDrawable(bitmap));

}

@Override

protected void initialized() {

blackPen = view.findViewById(R.id.black);

redPen = view.findViewById(R.id.red);

yellowPen = view.findViewById(R.id.yellow);

greenPen = view.findViewById(R.id.green);

pinkPen = view.findViewById(R.id.pink);

purplePen = view.findViewById(R.id.purple);

mPenView = view.findViewById(R.id.pen);

mClearView = view.findViewById(R.id.clear);

mEraserView = view.findViewById(R.id.eraser);

mSaveView = view.findViewById(R.id.save);

mQuitView = view.findViewById(R.id.quit);

initProgressDialog();

}

@Override

protected void initListener() {

// paletteView.setCallback(this);

mSaveView.setOnClickListener(this);

mQuitView.setOnClickListener(this);

mPenView.setOnClickListener(this);

mClearView.setOnClickListener(this);

mEraserView.setOnClickListener(this);

redPen.setOnClickListener(this);

yellowPen.setOnClickListener(this);

pinkPen.setOnClickListener(this);

greenPen.setOnClickListener(this);

purplePen.setOnClickListener(this);

blackPen.setOnClickListener(this);

mPenView.setSelected(true);

blackPen.setSelected(true);

}

public static HandWritingFragment newsInstance() {

return new HandWritingFragment();

}

@Override

public void widgetClick(View view) {

switch (view.getId()) {

case R.id.pen:

paletteView.setMode(PaletteView.Mode.DRAW);

paletteView.setPenColor(Color.BLACK);

mPenView.setSelected(true);

mEraserView.setSelected(false);

blackPen.setSelected(true);

greenPen.setSelected(false);

pinkPen.setSelected(false);

yellowPen.setSelected(false);

redPen.setSelected(false);

purplePen.setSelected(false);

break;

case R.id.eraser:

paletteView.setMode(PaletteView.Mode.ERASER);

mEraserView.setSelected(true);

mPenView.setSelected(false);

redPen.setSelected(false);

greenPen.setSelected(false);

pinkPen.setSelected(false);

yellowPen.setSelected(false);

purplePen.setSelected(false);

blackPen.setSelected(false);

break;

case R.id.clear:

paletteView.clear();

break;

case R.id.save:

progressDialog.show();

Bitmap bitmap = paletteView.buildBitmap();

handWritePrestener.saveImageToLocal(bitmap);

break;

case R.id.quit:

popOutBackStack();

break;

case R.id.black:

paletteView.setPenColor(Color.BLACK);

blackPen.setSelected(true);

greenPen.setSelected(false);

pinkPen.setSelected(false);

yellowPen.setSelected(false);

purplePen.setSelected(false);

redPen.setSelected(false);

break;

case R.id.red:

paletteView.setPenColor(Color.RED);

redPen.setSelected(true);

greenPen.setSelected(false);

pinkPen.setSelected(false);

yellowPen.setSelected(false);

purplePen.setSelected(false);

blackPen.setSelected(false);

break;

case R.id.green:

paletteView.setPenColor(Color.GREEN);

greenPen.setSelected(true);

pinkPen.setSelected(false);

yellowPen.setSelected(false);

purplePen.setSelected(false);

redPen.setSelected(false);

blackPen.setSelected(false);

break;

case R.id.yellow:

paletteView.setPenColor(Color.YELLOW);

yellowPen.setSelected(true);

redPen.setSelected(false);

greenPen.setSelected(false);

pinkPen.setSelected(false);

purplePen.setSelected(false);

blackPen.setSelected(false);

break;

case R.id.pink:

paletteView.setPenColor(Color.parseColor("#E771F6"));

pinkPen.setSelected(true);

redPen.setSelected(false);

greenPen.setSelected(false);

yellowPen.setSelected(false);

purplePen.setSelected(false);

blackPen.setSelected(false);

break;

case R.id.purple:

paletteView.setPenColor(Color.parseColor("#6376EB"));

purplePen.setSelected(true);

redPen.setSelected(false);

greenPen.setSelected(false);

yellowPen.setSelected(false);

pinkPen.setSelected(false);

blackPen.setSelected(false);

break;

}

}

private void initProgressDialog() {

progressDialog = new ProgressDialog(getActivity());

progressDialog.setMessage("正在保存,请稍候.....");

progressDialog.setCancelable(false);

}

@Override

public void onUndoRedoStatusChanged() {

}

@Override

public void onDestroy() {

super.onDestroy();

EventBus.getDefault().post(new HandWriteExitEvent());

handWritePrestener.onDestory();

upLoadImagePresenter.onDestory();

}

HandWriteView handWriteView = new HandWriteView() {

@Override

public void onError(String msg) {

if (progressDialog.isShowing())

progressDialog.dismiss();

ToastUtil.showToast(getContext(), msg);

}

@Override

public void onFileUploadSuccess(String fileid, String imgURL) {//上传成功

String teacherId = SPStoreUtil.getString(SystemConstant.sharedName, SystemConstant.teacherID);

String skjlID = SPStoreUtil.getString(SystemConstant.sharedName, SystemConstant.SKJLID);

SXBRequestBean sxbRequestBean = new SXBRequestBean();

sxbRequestBean.setSczid(teacherId);

sxbRequestBean.setSkjlid(skjlID);

sxbRequestBean.setFileid(fileid);

sxbRequestBean.setTplj(imgURL);

handWritePrestener.saveSXB(sxbRequestBean);

}

@Override

public void onSXBSave() {//保存成功

if (progressDialog.isShowing())

progressDialog.dismiss();

ToastUtil.showToast(getActivity(), "图片保存成功");

}

@Override

public void onLocalSaveImageSuccess(HandWriteSaveBean fileBean) {

upLoadImagePresenter.updateFile(

fileBean.getAppDir() + "/" + fileBean.getFileName()

, fileBean.getFileName());

Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

scanIntent.setData(Uri.fromFile(new File(fileBean.getAbsoluteFilePath())));

getContext().sendBroadcast(scanIntent);

}

};

}

效果还是比之前流畅多了。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐