偶然想到BimapShader 用法,发现实现水印功能,是分分钟的。所以不到十分钟,实现了,效果还不错。

啥是水印?

这个可以不用多说了,在文档的应用中是非常常用的。证明文档的所有权。通常是不可更改的。

为啥选用Drawable 实现

从Drawable 的注释可知,Drawable 相对于View 来说比较轻量,仔细体会可绘制的。不能和用户交互,也不能接受事件,静静的绘制。由于水印的场景确实不需要交互,而且可以方便的使用。所以作为Drawable 再好不过了

开始实现
  1. 接下来重头戏,想想水印是同一副图案出现n次,文字当然也可说是图案。如果采用canvas直接绘制图案。真的不好控制,麻烦。如果使用BitmapShader 那就容易多了。特别是Shader.TileMode.REPEAT 见识就是量身定做的。特别说一下TileMode还有TileMode.CLAMP,TileMode.MIRROR 两种。那怎么使用呢?当然是绘制一个RectF,这又不得不说Drawble 天生就是用来的。因为Drawable 的一个很重要方法,setBounds,用来确定绘制大小和位置。所以在绘制时候,直接调用getBounds() 就可使用。这里也是参考ShapeDrawable,BitmapDrawble 源码得到的。一般水印都是斜着的这怎么实现呢?两种方式,绘制的图案旋转,2,bitmapShader 旋转绘制图案。
  2. 拆解实现,首先要得到我们要绘制的图案。这里采用标准方式生成。
    fun makeMark(): Bitmap {
        val p = Paint().apply {
            isAntiAlias = true
            style = Paint.Style.STROKE
            color = Color.parseColor("#f5b8c2")
            textSize = 30f
        }
        val w = p.measureText(waterMark) + 20
        val bitmap = Bitmap.createBitmap(w.toInt(), 40, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        canvas.save()
        canvas.translate(10f, 5f)
        canvas.drawText(waterMark, 0f, p.textHeight() - p.descent(), p)
        canvas.restore()
        return bitmap
    }

以上代码可看到,通过水印文字的宽高,加上一定padding,通过canvas绘制到bitmap上,接下来绘制水印的画笔

    private val paint: Paint by lazy {
        Paint().apply {
            isAntiAlias = true
            style = Paint.Style.FILL
        }
    }

    init {
        val bs = BitmapShader(makeMark(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
        val m = Matrix()
        m.postRotate(45f)
        bs.setLocalMatrix(m)
        paint.shader = bs
    }

常规设置paint 之后,给设置BitmapShader,然后通过Martix旋转45度。接下来是绘制

    override fun draw(canvas: Canvas) {
        canvas.drawRect(bounds, paint)
    }

简单到不可相信,真的就只有一行代码。由于简单实现代码略粗糙,多多包涵。
我是源码

device-2018-12-27-233748.png

参考资料

自定义 Drawable
[译]Android:自定义Drawable教程