自定义SignView 签名(kotlin)

本文介绍如何使用Kotlin自定义一个SignView用于签名,详细讲解了xml布局配置和在Activity中的应用,提供了操作效果展示。

可直接复制使用

1.自定义SignView

package com.myapplication.signaturecustomization

import android.annotation.SuppressLint
import android.content.Context
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 java.util.ArrayList


class SignView : View {
    private var mPaint: Paint? = null
    private var mPath: Path? = null
    private var startX: Float = 0.toFloat()
    private var startY: Float = 0.toFloat()
    private var endX: Float = 0.toFloat()
    private var endY: Float = 0.toFloat()
    private var list: MutableList<SignModel>? = null
//    private var mBoundAry: Rect? = null
    private var bound: Int = 0
    private val down = "down"
    private val move = "move"
    private val end = "end"

    constructor(context: Context) : super(context) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        init()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    /**
     * 动态添加边框 暂时未用
     */
    @SuppressLint("DrawAllocation")
    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        val width = width
        val height = height
//        mBoundAry = Rect(bound, bound, width - bound, height - bound)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawLine(canvas)
    }


    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                startX = event.x
                startY = event.y
                setData(list!!, event.x, event.y, down)
                endX = event.x
                endY = event.y
                setData(list!!, event.x, event.y, move)
                postInvalidate()
            }
            MotionEvent.ACTION_MOVE -> {
                endX = event.x
                endY = event.y
                setData(list!!, event.x, event.y, move)
                postInvalidate()
            }
            MotionEvent.ACTION_UP -> setData(list!!, event.x, event.y, end)
            MotionEvent.ACTION_CANCEL -> setData(list!!, event.x, event.y, end)
        }
        return true
    }


    private fun init() {
        initPaint()
        initPath()
        initData()
    }

    private fun initPaint() {
        mPaint = Paint()
        mPaint!!.color = Color.BLACK
        mPaint!!.isAntiAlias = true
        mPaint!!.isDither = true
        mPaint!!.strokeWidth = 5f
        mPaint!!.style = Paint.Style.STROKE

    }


    private fun initPath() {
        mPath = Path()
        bound = 10
    }

    private fun initData() {
        list = ArrayList()
    }

    private fun setData(list: MutableList<SignModel>, x: Float, y: Float, type: String) {
        val signatuerModel = SignModel(x, y, type)
        list.add(signatuerModel)
    }

    private fun drawLine(canvas: Canvas) {
        mPath!!.moveTo(startX, startY)
        mPath!!.lineTo(endX, endY)
        startX = endX
        startY = endY
        canvas.drawPath(mPath!!, mPaint!!)
        //        canvas.drawRect(mBoundAry, mPaint);

    }

    fun clear() {
        list!!.clear()
        mPath!!.reset()
        postInvalidate()
    }

    fun back() {
        if (list != null && list!!.size > 0) {
            mPath!!.reset()
            val size = list!!.size - 1
            for (i in size downTo 0) {
                if (down == list!![i].type) {
                    list!!.removeAt(i)
                    break
                }
                list!!.removeAt(i)
            }

            val size3 = list!!.size - 1
            if (size3 > 0) {
                val path = Path()
                for (i in 0 until size3) {
                    val m = i + 1
                    startX = list!![i].x
                    startY = list!![i].y

                    endX = list!![m].x
                    endY = list!![m].y

                    if (end != list!![i].type) {
                        path.moveTo(startX, startY)
                        path.lineTo(endX, endY)
                    }
                    mPath!!.set(path)
                }
            }
            postInvalidate()

        }

    }

    fun size(): Int {
        return if (list != null) {
            list!!.size
        } else {
            0
        }

    }

    private inner class SignModel internal constructor(internal var x: Float, internal var y: Float, var type: String)
}

2.xml布局(signView 的路径是自己定义的路径)

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

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:layout_margin="@dimen/dp10"/>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:layout_margin="@dimen/dp15"
        android:background="@color/colorAzure">

        <com.myapplication.signaturecustomization.SignView
            android:id="@+id/signature_sv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/dp2"
            android:background="@color/colorWhite" />
    </FrameLayout>

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp40"
        android:layout_marginBottom="@dimen/dp5"
        android:background="@color/colorBackground"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:padding="@dimen/dp10"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent">


        <TextView
            android:id="@+id/signature_tv_cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/dp10"
            android:layout_marginLeft="@dimen/dp10"
            android:text="@string/cancel"
            android:textColor="@color/colorSignView"
            android:textSize="@dimen/sp15" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <!--<ImageView-->
            <!--android:id="@+id/signature_iv_clear"-->
            <!--android:layout_width="wrap_content"-->
            <!--android:layout_height="wrap_content"-->
            <!--android:src="@mipmap/shuaxin" />-->

        <!--<ImageView-->
            <!--android:id="@+id/signature_iv_back"-->
            <!--android:layout_width="wrap_content"-->
            <!--android:layout_height="wrap_content"-->
            <!--android:layout_marginStart="@dimen/dp30"-->
            <!--android:layout_marginLeft="@dimen/dp30"-->
            <!--android:src="@mipmap/chexiao" />-->

        <TextView
            android:id="@+id/signature_tv_ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/dp30"
            android:layout_marginLeft="@dimen/dp30"
            android:layout_marginEnd="@dimen/dp10"
            android:layout_marginRight="@dimen/dp10"
            android:text="@string/confirm"
            android:textColor="@color/colorSignView"
            android:textSize="@dimen/sp15"
            tools:ignore="RtlHardcoded" />
    </LinearLayout>

</LinearLayout>

3.使用activity

package com.myapplication.signaturecustomization

import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.myapplication.R
import kotlinx.android.synthetic.main.activity_sign_view.*

/**
 * @author  zdq
 * 创建时间: 2019/9/12 15:32
 */
class SignViewActivity : AppCompatActivity(), View.OnClickListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sign_view)
        initView()
    }

    private fun initView() {
        signature_tv_cancel.setOnClickListener(this)
        signature_tv_ok.setOnClickListener(this)

    }

    override fun onClick(v: View) {
        when (v.id) {
            R.id.signature_tv_cancel -> {
                signature_sv.clear()
            }
            R.id.signature_tv_ok -> {
                saveSignInfo(loadBitmapFromView(signature_sv))
            }
        }

    }
    private fun loadBitmapFromView(v: View): Bitmap {
        val w = v.width
        val h = v.height
        val bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        val c = Canvas(bmp)
        c.drawColor(Color.WHITE)
        v.layout(0, 0, w, h)
        v.draw(c)
        return bmp
    }

    private fun saveSignInfo(bitmap: Bitmap) {
        imageView.setImageBitmap(bitmap)
    }
}

ok,附上效果:

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值