Android實現(xiàn)手寫板功能
本文實例為大家分享了Android實現(xiàn)手寫板功能的具體代碼,供大家參考,具體內(nèi)容如下
自定義個一個手寫板的重點:
筆畫為一次down-move-up的集合
撤銷筆畫并非一次path的動作撤銷 應(yīng)該也是一次down-move -up的撤銷
為了更好的筆畫需要使用貝塞爾曲線來完成
效果如下:
截圖中清楚 的意思是清除 !
具體代碼如下:
package com.kyli.base.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; /** ?* 繪制畫板 ?*/ public class SignBoradView extends View { ? ? /*4個像素點*/ ? ? private int beierThreshold = 4; ? ? private float x = 0; ? ? private float y = 0; ? ? /*畫筆*/ ? ? private Paint mPaint; ? ? /*寬度*/ ? ? private int strokeWidth = 10; ? ? /*yanbse*/ ? ? private int color = Color.BLACK; ? ? /*當(dāng)前筆畫*/ ? ? private Path path; ? ? private int state = State.CLEAR; ? ? private interface State { ? ? ? ? /*畫板可以使用了*/ ? ? ? ? int START = 0; ? ? ? ? /*停止使用畫板*/ ? ? ? ? int STOP = 1; ? ? ? ? /*清空畫板*/ ? ? ? ? int CLEAR = 2; ? ? } ? ? private List<EveryPenPath> everyPenPaths = new ArrayList<>(); ? ? /*每一個筆畫*/ ? ? private static class EveryPenPath { ? ? ? ? public Path path; ? ? } ? ? public SignBoradView(Context context) { ? ? ? ? super(context); ? ? } ? ? public SignBoradView(Context context, @Nullable AttributeSet attrs) { ? ? ? ? super(context, attrs); ? ? } ? ? public SignBoradView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { ? ? ? ? super(context, attrs, defStyleAttr); ? ? } ? ? private void initPaint() { ? ? ? ? if (mPaint == null) { ? ? ? ? ? ? mPaint = new Paint(); ? ? ? ? ? ? mPaint.setStrokeWidth(strokeWidth); ? ? ? ? ? ? mPaint.setColor(color); ? ? ? ? ? ? mPaint.setStyle(Paint.Style.STROKE); ? ? ? ? ? ? mPaint.setAntiAlias(true); ? ? ? ? ? ? mPaint.setFlags(Paint.ANTI_ALIAS_FLAG); ? ? ? ? } ? ? } ? ? public void start() { ? ? ? ? state = State.START; ? ? ? ? initPaint(); ? ? } ? ? /*停止使用*/ ? ? public void stop() { ? ? ? ? state = State.STOP; ? ? } ? ? /*清空畫板*/ ? ? public void clear() { ? ? ? ? state = State.CLEAR; ? ? ? ? for (int i = everyPenPaths.size() - 1; i >= 0; i--) { ? ? ? ? ? ? EveryPenPath everyPenPath = everyPenPaths.get(i); ? ? ? ? ? ? everyPenPath.path.reset(); ? ? ? ? ? ? everyPenPath.path.close(); ? ? ? ? ? ? everyPenPath.path = null; ? ? ? ? } ? ? ? ? everyPenPaths.clear(); ? ? ? ? invalidate(); ? ? } ? ? public void back() { ? ? ? ? int count = everyPenPaths.size(); ? ? ? ? if (count < 1) ? ? ? ? ? ? return; ? ? ? ? EveryPenPath everyPenPath = everyPenPaths.get(count - 1); ? ? ? ? everyPenPath.path.reset(); ? ? ? ? everyPenPath.path.close(); ? ? ? ? everyPenPath.path = null; ? ? ? ? everyPenPaths.remove(count - 1); ? ? ? ? invalidate(); ? ? } ? ? @Override ? ? protected void onDraw(Canvas canvas) { ? ? ? ? super.onDraw(canvas); ? ? ? ? if (state == State.START) { ? ? ? ? ? ? /*先繪制完整筆畫*/ ? ? ? ? ? ? for (EveryPenPath e : everyPenPaths) { ? ? ? ? ? ? ? ? canvas.drawPath(e.path, mPaint); ? ? ? ? ? ? } ? ? ? ? ? ? //當(dāng)前進(jìn)行中的 ?path!=null ? ? ? ? ? ? if (path != null) { ? ? ? ? ? ? ? ? canvas.drawPath(path, mPaint); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? @Override ? ? public boolean onTouchEvent(MotionEvent event) { ? ? ? ? if (state == State.START) { ? ? ? ? ? ? if (event.getAction() == MotionEvent.ACTION_UP) { ? ? ? ? ? ? ? ? actionUp(event); ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } ? ? ? ? ? ? if (event.getAction() == MotionEvent.ACTION_MOVE) { ? ? ? ? ? ? ? ? actionMove(event); ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } ? ? ? ? ? ? if (event.getAction() == MotionEvent.ACTION_DOWN) { ? ? ? ? ? ? ? ? actionDown(event); ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return super.onTouchEvent(event); ? ? } ? ? private void actionUp(MotionEvent event) { ? ? ? ? actionMove(event); ? ? ? ? /*構(gòu)成一個筆畫*/ ? ? ? ? EveryPenPath everyPenPath = new EveryPenPath(); ? ? ? ? everyPenPath.path = path; ? ? ? ? everyPenPaths.add(everyPenPath); ? ? ? ? //將當(dāng)前畫筆置位null; ? ? ? ? path = null; ? ? } ? ? /**/ ? ? private void actionMove(MotionEvent event) { ? ? ? ? /*每次移動去繪制貝塞爾曲線*/ ? ? ? ? float cX = event.getX(); ? ? ? ? float cY = event.getY(); ? ? ? ? float dX = Math.abs(cX - x);//變化量 ? ? ? ? float dY = Math.abs(cY - y); ? ? ? ? if (dX >= beierThreshold || dY >= beierThreshold) { ? ? ? ? ? ? float rX = x + (cX - x) / 2; ? ? ? ? ? ? float rY = y + (cY - y) / 2; ? ? ? ? ? ? path.quadTo(rX, rY, cX, cY); ? ? ? ? ? ? //下次的x 域y 將重新計算 ? ? ? ? ? ? x = cX; ? ? ? ? ? ? y = cY; ? ? ? ? } ? ? } ? ? /*開始時*/ ? ? private void actionDown(MotionEvent event) { ? ? ? ? path = new Path(); ? ? ? ? x = event.getX(); ? ? ? ? y = event.getY(); ? ? ? ? path.moveTo(x, y); ? ? } ? ? public void setBeierThreshold(int beierThreshold) { ? ? ? ? this.beierThreshold = beierThreshold; ? ? } ? ? public void setStrokeWidth(int strokeWidth) { ? ? ? ? this.strokeWidth = strokeWidth; ? ? } ? ? public void setColor(int color) { ? ? ? ? this.color = color; ? ? } ? ? public Bitmap getResult(int bgColor) { ? ? ? ? if (everyPenPaths.size() == 0) ? ? ? ? ? ? return null; ? ? ? ? Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); ? ? ? ? Canvas canvas = new Canvas(bitmap); ? ? ? ? canvas.drawColor(bgColor); ? ? ? ? for (int i = 0; i < everyPenPaths.size(); i++) { ? ? ? ? ? ? if (mPaint == null) { ? ? ? ? ? ? ? ? initPaint(); ? ? ? ? ? ? } ? ? ? ? ? ? canvas.drawPath(everyPenPaths.get(i).path, mPaint); ? ? ? ? } ? ? ? ? return bitmap; ? ? } ? ? public Bitmap getResult() { ? ? ? ? return getResult(Color.WHITE); ? ? } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中實現(xiàn)長按修改ListView對象的內(nèi)容
這篇文章主要給大家介紹了在Android中實現(xiàn)長按修改ListView對象內(nèi)容的相關(guān)資料,文中給出了完整的示例代碼,相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-02-02詳解 android 光線傳感器 light sensor的使用
這篇文章主要介紹了詳解 android 光線傳感器 light sensor的使用的相關(guān)資料,需要的朋友可以參考下2017-06-06Android實現(xiàn)面包屑功能的代碼(支持Fragment聯(lián)動)
這篇文章主要介紹了Android實現(xiàn)面包屑功能的代碼(支持Fragment聯(lián)動),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05Android startActivityForResult實例詳解
這篇文章主要介紹了Android startActivityForResult實例詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05Android實現(xiàn)自定義圓角對話框Dialog的示例代碼
項目中多處用到對話框,本篇文章主要介紹了Android實現(xiàn)圓角對話框Dialog的示例代碼,有興趣的可以了解一下。2017-03-03