Android自定义签名View (Kotlin)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bobo1127881870/article/details/80333194

好久没有写博客了,今天再次“提笔”回顾一下安卓的自定义view,同时也可以复习一下Kotlin的用法。依然放在首位的必须是效果图:

这字体有木有很高端大气上档次的感觉偷笑,写完以后发现我的字体别具一格啊,不做书法家都有点屈才大笑(打住),效果图奉上以后就是我们代码的实现了。最基本的画笔(paint),画布(canvas)是要有的,没什么可详细说的,代码里面每行都有注释简单明了,最重要的是可以直接复制黏贴使用:

package com.sungu.refreshgridviewtest

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Base64
import android.view.MotionEvent
import android.view.View
import java.io.*
/**
 * Created by bobo on 2018/5/16.
 */
class SignView: View{
    lateinit var mPathPaint:Paint   //画笔
    lateinit var cavas :Canvas        //画布
    lateinit var path : Path          //路径
    var mPreX : Float = 0.0f         //辅助点x方向坐标
    var mPreY : Float =0.0f        //辅助点y方向坐标

    //一个参数的构造函数
    constructor(context: Context):super(context){
        init(context)

    }
    //两个参数的构造函数(切记他继承的也要是两个函数的构造,否则的话,嘿嘿你懂的)
    constructor(context: Context,attributeSet: AttributeSet):super(context,attributeSet){
        init(context,attributeSet)

    }

    //实例化画笔的一些属性值
    fun init(context: Context,attributeSet: AttributeSet?=null){
        mPathPaint = Paint(Paint.ANTI_ALIAS_FLAG)     //绘制时抗锯齿
        mPathPaint.isAntiAlias=true      //也是辅助抗锯齿(没感觉出效果来)
        mPathPaint.isDither = true   //设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
        mPathPaint.style = Paint.Style.STROKE     //画笔的样式
        mPathPaint.strokeWidth = 10F         //画笔的粗细程度
        mPathPaint.color = Color.parseColor("#ff3f4a57")    //画笔的颜色
        mPathPaint.strokeJoin = Paint.Join.ROUND      //线段结束处的形状
        mPathPaint.strokeCap = Paint.Cap.ROUND        //线段开始结束处的形状
    }

    //测量的方法
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        resetSign()
    }

    //重置的方法
    private fun resetSign(){
        path = Path()
        cavas= Canvas()
    }

    //开始画路径的方法
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas != null) {
            canvas.drawPath(path, mPathPaint)
        }

    }

    //最关键的touch事件监听
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.getAction()) {
            MotionEvent.ACTION_DOWN -> {
                mPreX = event.getX()
                mPreY = event.getY()
                path.moveTo(mPreX, mPreY)
            }
            MotionEvent.ACTION_MOVE -> {
                val x = event.getX()
                val y = event.getY()
                //绘制圆滑曲线(贝塞尔曲线)
                path.quadTo(mPreX, mPreY, x, y)
                mPreX = x
                mPreY = y
            }
            MotionEvent.ACTION_UP -> {
                path.lineTo(event.getX(), event.getY())
                cavas.drawPath(path, mPathPaint)
            }
        }
        //更新View
        invalidate()
        return true
    }

    /**
     * 保存bitmap到文件
     *
     * @param fileapth
     * @return 成功返回true,反之false
     */
    fun SaveBitmapToFile(fileapth: String): Boolean {
        val file = File(fileapth)
        if (file.exists()) {
            val bitmap=getBitMap()
            var fos: FileOutputStream? = null
            try {
                fos = FileOutputStream(file)
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
                return true
            } catch (e: FileNotFoundException) {
                e.printStackTrace()
                return false
            } finally {
                try {
                    fos!!.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }

            }
        } else
            return false
    }

    fun reset() {
        resetSign()
        invalidate()
    }

    /**
     * 获取BitMap图片
     * */
    fun getBitMap():Bitmap{
        // 创建一个bitmap 根据我们自定义view的大小
        val returnedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        // 绑定canvas
        val canvas = Canvas(returnedBitmap)
        // 获取视图的背景
        val bgDrawable = background
        if (bgDrawable != null)
        // 如果有就绘制
            bgDrawable.draw(canvas)
        else
        // 没有就绘制白色
            canvas.drawColor(Color.WHITE)
        // 绘制
            draw(canvas)
        return returnedBitmap
    }

    companion object {
        /**
         * 保存为base64形式
         * */
        fun saveBitMapToBase64(bitmap : Bitmap) : String{
            var result : String= null.toString()
            var baos: ByteArrayOutputStream? = null
            try {
                if (bitmap != null) {
                    baos = ByteArrayOutputStream()
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)

                    baos!!.flush()
                    baos!!.close()

                    val bitmapBytes = baos!!.toByteArray()
                    result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT)
                }
            } catch (e: IOException) {
                e.printStackTrace()
            } finally {
                try {
                    if (baos != null) {
                        baos!!.flush()
                        baos!!.close()
                    }
                } catch (e: IOException) {
                    e.printStackTrace()
                }

            }
            return result
        }


        /**
         * 将base64形式转换为图片
         * */
        fun base64ToBitMap(base64 : String) : Bitmap{
            val bytes = Base64.decode(base64, Base64.DEFAULT)
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
        }
    }


}

直接使用的xml布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/btn_ok"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:gravity="center"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/btn_reset"
        android:text="完成"/>
    <Button
        android:id="@+id/btn_reset"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:gravity="center"
        app:layout_constraintLeft_toRightOf="@+id/btn_ok"
        app:layout_constraintRight_toLeftOf="@+id/btn_cancel"
        app:layout_constraintBottom_toBottomOf="parent"
        android:text="重置"/>
    <Button
        android:id="@+id/btn_cancel"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:gravity="center"
        app:layout_constraintLeft_toRightOf="@+id/btn_reset"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:text="取消"/>
    <com.sungu.refreshgridviewtest.SignView
        android:id="@+id/zdy_signView"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="#CC9933"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/btn_ok"
       />
</android.support.constraint.ConstraintLayout>

然后就是控制器activity的代码了

import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity(),View.OnClickListener{


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btn_ok.setOnClickListener(this)
        btn_reset.setOnClickListener(this)
        btn_cancel.setOnClickListener(this)
    }

    override fun onClick(p0: View) {
        when(p0.id){
            R.id.btn_ok -> {
                var reource=SignView.saveBitMapToBase64(zdy_signView.getBitMap())
                val intent=Intent()
                intent.setClass(this@MainActivity,TestImageActivity::class.java)
                intent.putExtra(TestImageActivity.CONSTANT,reource)
                startActivity(intent)
            }
            R.id.btn_reset -> {
                zdy_signView.reset()
            }
            R.id.btn_cancel -> {
                finish()
            }
        }
    }
}

我这里直接用的base64的方式传递(项目需要),接下来就是将保存的图片显示出来代码:

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_test.*

/**
 * Created by bobo on 2018/5/16.
 */
class TestImageActivity : AppCompatActivity() {

    //静态属性
    companion object {
        val CONSTANT : String = "RESOUCE"
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        initIntent()
    }
    fun initIntent(){
        var result=intent.getStringExtra(CONSTANT)
        iv_show.setImageBitmap(SignView.base64ToBitMap(result))
    }
}
大功告成。所有的和自定义签名view的代码都在这儿了,欢迎使用,如有问题自己负责(呵呵,评论出来一起改进)。
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页