Android:手签名卡顿优化方案

我正在参加「掘金·启航计划」,这是我参加的第4篇文章。

从之前的 实现一个自定义有限制区域的图例(角度自识别)涂鸦工具类 三部曲到 自定义View实现签名带笔锋效果 基本完成了一整套关于手签名的实现流程。这篇主要说说关于手签名随着内容越来越多出现越来越卡的优化方案。

首先让我们想想为什么会随着内容的增多变得越来越卡呢?

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    //手动画图
    drawPic()
}

//画图
private fun drawPic() {
    //绘制所有线条
    for (i in allList.indices) {
        drawLines(allList[i], paints[i])
    }
    //实时线条
    drawLines(allPoints, paint)
}

override fun onTouchEvent(event: MotionEvent): Boolean {
    super.onTouchEvent(event)
    val p = Point(event.x.toInt(), event.y.toInt())
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {//用户按下
            ......
        }
        MotionEvent.ACTION_UP -> {//用户松开
            ......
            postInvalidate() //重绘
        }
        MotionEvent.ACTION_MOVE -> {//移动
            ......
            postInvalidate() //重绘
        }
    }
    return true
}

可以看到,在用户不停移动和抬起的时候都在不停重绘以便界面能实时显示当前的线条。随着内容的增多,则线条累积越多,在移动的时候会不停绘制大量线条,那必定会越来越卡。

如何才能解决这个问题呢?

答案是:避免大量绘制和重绘。

设想我们能不能只绘制当前正在签名的这条实时线,当这条线绘制完成后我们将其保存为一个Bitmap,并将该Bitmap绘制为背景。绘制第二条线完成后生成第二个Bitmap,此时的Bitmap包含了第一个Bitmap和第二条线的内容。以此类推,必然也能达到之前的效果。并且现在绘制的内容其实最多就只有最后一张Bitmap和当前实时线条。

//创建bitmap
mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
//mCanva用于绘制历史线条,仅在抬起时绘制
mCanvas = new Canvas(mBitmap);

@Override
protected void onDraw(Canvas canvas) {
    //绘制bitmap
    canvas.drawBitmap(mBitmap, 0, 0, mPaint);
    ......
    super.onDraw(canvas);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
         ......
    case MotionEvent.ACTION_UP:
         bitmaps.addBitmap(mBitmap);//添加历史图片
         break;

由于使用了Bitmap,当然涉及到内存分配和图片回收的相关处理,这里可以自行网上解决,本文不做分享。关于签名的撤回、取消、清空对应的就是对bitmaps集合的操作,我们本地需要维护一个bitmaps的管理类。

好了,到这里基本上满屏画满内容也不会出现明显的卡顿了,希望对大家有所帮助。  

我是一个喜爱Jay、Vae的安卓开发者,喜欢结交五湖四海的兄弟姐妹,欢迎大家到沸点来点歌!