網站首頁 編程語言 正文
本文實例為大家分享了Android實現手寫板功能的具體代碼,供大家參考,具體內容如下
自定義個一個手寫板的重點:
筆畫為一次down-move-up的集合
撤銷筆畫并非一次path的動作撤銷 應該也是一次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;
? ? /*當前筆畫*/
? ? 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);
? ? ? ? ? ? }
? ? ? ? ? ? //當前進行中的 ?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);
? ? ? ? /*構成一個筆畫*/
? ? ? ? EveryPenPath everyPenPath = new EveryPenPath();
? ? ? ? everyPenPath.path = path;
? ? ? ? everyPenPaths.add(everyPenPath);
? ? ? ? //將當前畫筆置位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);
? ? }
}
原文鏈接:https://blog.csdn.net/likui19921224/article/details/122602528
相關推薦
- 2022-04-17 SpringBoot中,redis的key和value為基本類型時需要注意的
- 2022-01-06 Spring Aware接口詳解
- 2024-04-06 linux環境docker安裝redis(AOF和RDB持久化)
- 2022-06-25 PyTorch模型保存與加載實例詳解_python
- 2023-03-05 useCallback和useMemo的正確用法詳解_React
- 2022-05-26 Flutter自定義年月日倒計時_Android
- 2022-03-17 .net?程序通過?crontab?無法啟動手動執行腳本啟動的方法_實用技巧
- 2022-06-19 Python?matplotlib實現條形統計圖_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支