Android 自定義View手寫簽名並保存圖片

来源:https://www.cnblogs.com/YyyyQ/archive/2020/03/20/12529799.html
-Advertisement-
Play Games

GIF壓縮有問題,運行很順滑!!! 1.自定義View——支持設置畫筆顏色,畫筆寬度,畫板顏色,清除畫板,檢查是否有簽名,保存畫板圖片(複製粘貼可直接使用) /** * Created by YyyyQ on 2020/3/5. * 電子簽名 */ public class SignatureVie ...


    GIF壓縮有問題,運行很順滑!!!

 

 1.自定義View——支持設置畫筆顏色,畫筆寬度,畫板顏色,清除畫板,檢查是否有簽名,保存畫板圖片(複製粘貼可直接使用)

/**
 * Created by YyyyQ on 2020/3/5.
 * 電子簽名
 */
public class SignatureView extends View {

    private Context context;
    //X軸起點
    private float x;
    //Y軸起點
    private float y;
    //畫筆
    private final Paint paint = new Paint();
    //路徑
    private final Path path = new Path();
    //畫布
    private Canvas canvas;
    //生成的圖片
    private Bitmap bitmap;
    //畫筆的寬度
    private int paintWidth = 10;
    //簽名顏色
    private int paintColor = Color.BLACK;
    //背景顏色
    private int backgroundColor = Color.WHITE;
    //是否已經簽名
    private boolean isTouched = false;

    //簽名開始與結束
    public interface Touch {
        void OnTouch(boolean isTouch);
    }

    private Touch touch;


    public SignatureView(Context context) {
        super(context);
        init(context);
    }

    public SignatureView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SignatureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        this.context = context;
        //抗鋸齒
        paint.setAntiAlias(true);
        //樣式
        paint.setStyle(Paint.Style.STROKE);
        //畫筆顏色
        paint.setColor(paintColor);
        //畫筆寬度
        paint.setStrokeWidth(paintWidth);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //創建於view大小一致的bitmap
        bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        canvas = new Canvas(bitmap);
        canvas.drawColor(backgroundColor);
        isTouched = false;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (touch != null) touch.OnTouch(true);
        switch (event.getAction()) {
            //手指按下
            case MotionEvent.ACTION_DOWN:
                touchDwon(event);
                break;
            //手指移動
            case MotionEvent.ACTION_MOVE:
                isTouched = true;
                if (touch != null) touch.OnTouch(false);
                touchMove(event);
                break;
            //手指抬起
            case MotionEvent.ACTION_UP:
                canvas.drawPath(path, paint);
                path.reset();
                break;
        }
        // 更新繪製
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫此次筆畫之前的簽名
        canvas.drawBitmap(bitmap, 0, 0, paint);
        // 通過畫布繪製多點形成的圖形
        canvas.drawPath(path, paint);
    }


    //手指按下的方法
    private void touchDwon(MotionEvent event) {
        //重置繪製路徑
        path.reset();
        float downX = event.getX();
        float downY = event.getY();
        x = downX;
        y = downY;
        //繪製起點
        path.moveTo(downX, downY);
    }

    //手指滑動的方法
    private void touchMove(MotionEvent event) {
        //當前的x,y坐標點
        final float moveX = event.getX();
        final float moveY = event.getY();
        //之前的x,y坐標點
        final float previousX = x;
        final float previousY = y;
        //獲取絕對值
        final float dx = Math.abs(moveX - previousX);
        final float dy = Math.abs(moveY - previousY);
        if (dx >= 3 || dy >= 3) {
            float cX = (moveX + previousX) / 2;
            float cY = (moveY + previousY) / 2;
            path.quadTo(previousX, previousY, cX, cY);
            x = moveX;
            y = moveY;
        }
    }

    /**
     * 設置畫筆顏色
     *
     * @param paintColor
     */
    public void setPaintColor(int paintColor) {
        this.paintColor = paintColor;
        paint.setColor(paintColor);
    }

    /**
     * 設置畫筆寬度
     *
     * @param paintWidth
     */
    public void setPaintWidth(int paintWidth) {
        this.paintWidth = paintWidth;
        paint.setStrokeWidth(paintWidth);
    }

    /**
     * 設置畫板顏色
     *
     * @param canvasColor
     */
    public void setCanvasColor(int canvasColor) {
        this.backgroundColor = canvasColor;
    }


    /**
     * 清除畫板
     */
    public void clear() {
        if (canvas != null) {
            isTouched = false;
            //更新畫板
            paint.setColor(paintColor);
            paint.setStrokeWidth(paintWidth);
            canvas.drawColor(backgroundColor, PorterDuff.Mode.CLEAR);
            invalidate();
        }
    }

    /**
     * 獲取畫板的Bitmap
     *
     * @return
     */
    public Bitmap getBitmap() {
        setDrawingCacheEnabled(true);
        buildDrawingCache();
        Bitmap bitmap = getDrawingCache();
        setDrawingCacheEnabled(false);
        return bitmap;
    }

    /**
     * 是否有簽名
     *
     * @return
     */
    public Boolean getSigstatus() {
        return isTouched;
    }

    /**
     * 保存畫板
     *
     * @param path 保存到路徑
     */
    @SuppressLint("WrongThread")
    public Boolean save(String path) throws IOException {
        Bitmap bitmap = this.bitmap;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
        byte[] buffer = bos.toByteArray();
        if (buffer != null) {
            File file = new File(path);
            if (file.exists()) {
                file.delete();
            }
            OutputStream outputStream = new FileOutputStream(file);
            outputStream.write(buffer);
            outputStream.close();
            return true;
        } else {
            return false;
        }
    }


}

 2.xml佈局引用自定義View(註意包名)

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!--自定義view的絕對路徑-->
    <com.example.customviewdemo.view.SignatureView
        android:id="@+id/signature"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#fff" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_margin="20dp"
        android:orientation="horizontal">

        <Button
            android:id="@+id/clear"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="清除" />

        <Button
            android:id="@+id/isSignature"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="是否簽名" />

        <Button
            android:id="@+id/save"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="保存" />

    </LinearLayout>

</LinearLayout>

 

3.Activity調用

/**
* Created by YyyyQ on 2020/3/9.
*/
public class SignatureActivity extends AppCompatActivity {


@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signature);
SignatureView signatureView = findViewById(R.id.signature);
//設置畫筆顏色(可以不設置--預設畫筆寬度10,畫筆顏色黑,背景顏色白)
signatureView.setPaintColor(Color.BLACK);
signatureView.setPaintWidth(20);
signatureView.setCanvasColor(Color.WHITE);
//清除
Button clear = findViewById(R.id.clear);
clear.setOnClickListener(view -> {
signatureView.clear();
//設置畫筆顏色(可以不設置--預設畫筆寬度10,畫筆顏色黑,背景顏色白)
signatureView.setPaintColor(Color.BLACK);
signatureView.setPaintWidth(20);
signatureView.setCanvasColor(Color.WHITE);
});
//是否含有簽名
Button isSignature = findViewById(R.id.isSignature);
isSignature.setOnClickListener(view -> {
if (signatureView.getSigstatus()) {
Toast.makeText(SignatureActivity.this, "有簽名", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SignatureActivity.this, "無簽名", Toast.LENGTH_SHORT).show();
}
});
//保存
Button save = findViewById(R.id.save);
save.setOnClickListener(view -> {
try {
if (signatureView.save("/sdcard/YyyyQ.png")) {
Toast.makeText(SignatureActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SignatureActivity.this, "保存失敗", Toast.LENGTH_SHORT).show();
}

} catch (IOException e) {
e.printStackTrace();
}

});

}
}

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Oracle VM VirtualBox NatNetwork 設置(提供虛擬主機外網訪問) 1.1、進入全局設定 選擇網路 添加NAT網路 1.2、設置NAT 二、VirtualBox Host-Only設定(提供內網訪問) 2.1、配置Host-Only設置(建議設置順序為 網卡設定 DHC ...
  • 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 ...
  • ORA-00001: 違反唯一約束條件 (.) ORA-00017: 請求會話以設置跟蹤事件 ORA-00018: 超出最大會話數 ORA-00019: 超出最大會話許可數 ORA-00020: 超出最大進程數 () ORA-00021: 會話附屬於其它某些進程;無法轉換會話 ORA-00022: ...
  • 問題描述:本來還在愉快的工作中,突然同時通知客戶主資料庫無法登陸了,心中莫名的一緊,趕緊登陸資料庫查看,發現只有sys賬號可以正常登錄,其他賬號登錄均提示ORA00257錯誤。趕緊百度一下,看大致的意思為歸檔日誌寫滿了、閃回日誌寫滿了。根據網上提供的方法進行查看:select * from v$re... ...
  • Mapping (映射)類似關係型資料庫中的表的結構定義。我們將數據以 JSON 格式存入到 ElasticSearch 中後,在搜索引擎中 JSON 欄位映射對應的類型,這時需要 mapping 來定義內容的類型。 ...
  • 前言: 有時候,連接MySQL的會話經常會異常退出,錯誤日誌里會看到"_Got an error reading communication packets_"類型的告警。本篇文章我們一起來討論下該錯誤可能的原因以及如何來規避。 1.狀態變數Aborted_clients和Aborted_conne ...
  • 場景 Centos中Redis的下載編譯與安裝(超詳細): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103967334 Redis的啟動和關閉(前臺啟動和後臺啟動): https://blog.csdn.net/BADAO_ ...
  • 1.從SQLite官網下載所需要的安裝包文件,安裝之後在對應的bin文件夾下獲取所需要的dll文件,主要包括system.data.sqlite.dll,以及sqlite.interop.dll;; 2.將此部分dll複製到生成解決方案文件目錄,並將system.data.sqlite.dll文件添 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...