好久没有写博客了,今天再次“提笔”回顾一下安卓的自定义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:///apk/res/android"
xmlns:app="http:///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 .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(){
.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)
}
.btn_reset -> {
zdy_signView.reset()
}
.btn_cancel -> {
finish()
}
}
}
}我这里直接用的base64的方式传递(项目需要),接下来就是将保存的图片显示出来代码:
import android.os.Bundle
import .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的代码都在这儿了,欢迎使用,如有问题自己负责(呵呵,评论出来一起改进)。
















