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

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

下面看一下效果:

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

下面看一下实现代码:

/** * @name DrawingView * @package com.example.ui.customView * @author 345 QQ:1831712732 * @time 2020/5/26 20:46 * @description 画板 */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        }    }    /**     * 返回 bitmap     * @param blank :边距     */    fun getBitmap(blank: Int): Bitmap? {        return cropCanvas(blank.toFloat())    }    /**     * 获取图片 file     */    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)    }    /**     * 保存图片到本地     * @param displayName 图片名称,注意需要加上后缀名 .png     * 注意名字不能重复,否则无法保存     */    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    }    /**     * 剪裁画布把多余的画布去掉只保留签名部分     *     * @param blank 边距     */    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()        }    }    /**     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)     */    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()            }        }

源码地址

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

更多相关文章

  1. Android(安卓)图片压缩并保存的方法
  2. Android内部存储和外部存储以及缓存清理和内存清理!
  3. bitmap与canvas android
  4. Android(安卓)savedInstanceState的作用和用法
  5. (转载)Android应用程序签名系统的签名(SignApk.jar)
  6. android捕鱼达人修改方法(反编译、修改、打包)
  7. android????fragment?????FragmentArgs??
  8. Android(安卓)PreferenceActivity浅析
  9. Android——数据存储(四种方式之二)读写SD卡

随机推荐

  1. CI/CD笔记-Jenkins的安装部署
  2. 「CI集成」基于Jest Mock API对业务逻辑
  3. Docker_学习笔记系列之仓库
  4. linux_学习之防火墙firewalld
  5. Docker_学习笔记系列之镜像
  6. CI/CD笔记-Gitlab安装部署
  7. Docker_学习笔记系列之容器
  8. Python_学习之多协程
  9. Docker_学习笔记系列之docker-secret
  10. Docker_学习笔记系列之CentOs7安装docker