PaletteView手写板优化

优化方式

  • 增加触摸点个数
  • 减少每次刷新的区域(每次只刷新一个小矩形区域)

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

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<DrawingInfo> mDrawingList;
    private List<DrawingInfo> 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);
        }


    };

}

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值