Android 自定义签字板

   日期:2020-05-29     浏览:87    评论:0    
核心提示:自定义签字板,实现名字居中,增加边距等。可直接获取到 bitmap,uri,File ,并且直接进行保存到手机,支持 Android Q移动开发

自定义签字板,实现名字居中,增加边距等

可直接获取到 bitmap,uri,File ,并且直接进行保存到手机,支持 Android Q

下面看一下效果:

上面清除的展示了名字居中的效果,并且四周设置了内边距

下面看一下实现代码:



class DrawingView : View {

    private lateinit var mPaint: Paint
    private lateinit var mPath: Path
    private var cacheBitmap //用户保存签名的Bitmap
            : Bitmap? = null
    private var cacheCanvas //用户保存签名的Canvas
            : Canvas? = null

    //位置
    private var mLeft: Float = 0f
    private var mRight: Float = 0f
    private var mTop: Float = 0f
    private var mBottom: Float = 0f

    //边距
    private var mPadding = 20f

    //线宽度
    private var mPaintWidth = 10f

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


    private fun init() { //初始化画笔
        mPaint = Paint()
        mPaint.style = Paint.Style.STROKE
        mPaint.color = Color.BLACK
        mPaint.strokeWidth = mPaintWidth
        mPath = Path()
    }

    
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        cacheBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        cacheCanvas = Canvas(cacheBitmap!!)
        //设置背景色为透明
        cacheCanvas?.drawColor(Color.WHITE)
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                //路径起点
                mPath.moveTo(event.x, event.y)
                if (mLeft == 0f) {
                    mLeft = event.x
                }
                if (mTop == 0f) {
                    mTop = event.y
                }
                setVertexCoordinates(event.x, event.y)
            }
            MotionEvent.ACTION_MOVE -> {
                mPath.lineTo(event.x, event.y)
                postInvalidate()
                //限制滑动的位置
                if (event.x < width && event.x >= 0) {
                    if (event.y < height && event.y >= 0) {
                        //如果是第二次按下,也需要记录位置
                        setVertexCoordinates(event.x, event.y)
                    }
                }
            }
            MotionEvent.ACTION_UP -> //将签名绘制到缓存画布上
                cacheCanvas?.drawPath(mPath, mPaint)
        }
        return true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //绘制签名路径
        canvas.drawPath(mPath, mPaint)
    }

    
    fun resetCanvas() {
        mPath.reset()
        cacheBitmap = null
        cacheCanvas = null
        cacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        cacheCanvas = Canvas(cacheBitmap!!)
        //设置背景色为透明
        cacheCanvas?.drawColor(Color.WHITE)
        mBottom = 0f
        mTop = mBottom
        mRight = mTop
        mLeft = mRight
        postInvalidate()
    }

    
    private fun setVertexCoordinates(x: Float, y: Float) {
        if (x > mRight) {
            mRight = x
        }
        if (x < mLeft) {
            mLeft = x
        }
        if (y > mBottom) {
            mBottom = y
        }
        if (y < mTop) {
            mTop = y
        }
    }

    
    fun getBitmap(blank: Int): Bitmap? {
        return cropCanvas(blank.toFloat())
    }

    
    fun getFile(): File? {
        val bitmap = getBitmap(15) ?: return null
        val uri = save(bitmap, "${System.currentTimeMillis()}.png")
                ?: throw FileNotFoundException("文件未找到")
        val query = context.contentResolver.query(uri, arrayOf(MediaStore.Images.Media.DATA), null, null, null)
        query?.moveToFirst()
        val index = query?.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
        val path = query!!.getString(index!!)
        if (path == null) {
            ToastUtils.showText("获取失败")
            query.close()
        }
        return File(path)
    }

    
    fun save(displayName: String): Uri? {
        val bitmap = getBitmap(15) ?: return null
        return save(bitmap, displayName)
    }

    fun save(bitmap: Bitmap, displayName: String): Uri? {
        val values = ContentValues()
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
        values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
        } else {
            values.put(MediaStore.MediaColumns.DATA, "${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/$displayName")
        }
        val uri = context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        if (uri != null) {
            val outputStream = context.contentResolver.openOutputStream(uri)
            if (outputStream != null) {
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
                outputStream.close()
            }
            ToastUtils.showText("完成")
            return uri
        }
        return null
    }

    
    private fun cropCanvas(): Bitmap? {
        return cropCanvas(mPadding)
    }

    private fun cropCanvas(padding: Float): Bitmap? {
        var right = (mRight - mLeft)
        if (right + (padding * 2) < width) {
            mLeft -= padding
            right += padding
        }
        var height = (mBottom - mTop)
        if (height + (padding * 2) < getHeight()) {
            mTop -= padding
            height += padding
        }

        if (right <= padding && height <= padding) {
            ToastUtils.showText("请进行签名")
            return null
        }

        val dip2px = dip2px(padding)
        //裁切签名的部分
        val cropBitmap = Bitmap.createBitmap(cacheBitmap!!, mLeft.toZero(), mTop.toZero(), right.toZero(), height.toZero())

        //设置边距
        val bitmap = Bitmap.createBitmap((cropBitmap.width + (dip2px * 2)), (cropBitmap.height + (dip2px * 2)), Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        canvas.drawColor(Color.WHITE)
        canvas.drawBitmap(cropBitmap, dip2px.toFloat(), dip2px.toFloat(), mPaint)
        return bitmap
    }

    private fun Float.toZero(): Int {
        return if (this < 0f) {
            0
        } else {
            this.toInt()
        }
    }

    
    private fun dip2px(dpValue: Float): Int {
        val scale = resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }
}

使用如下:

 //画板
        activity_drawing.setOnClickListener {
            val dialog = FastDialog.Builder(this)
                    .setContentView(R.layout.layout_drawing)
                    .setWidth(0.7f)
                    .build()
            dialog.show()
            val drawingView = dialog.getView<DrawingView>(R.id.layout_drawing)
            dialog.setOnClickListener(R.id.layout_save) {
                //这里使用的是 getFile,你也可以直接调用 getBitmap 等
                val file = drawingView?.getFile()
                val bitmap = BitmapFactory.decodeFile("${file?.path}")
                activity_views_image.setImageBitmap(bitmap)
            }
            dialog.setOnClickListener(R.id.layout_reset) {
                ToastUtils.showCenterText("重置")
                drawingView?.resetCanvas()
            }
        }

源码地址

如有问题,还请指出,谢谢!

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服