注册

高仿PPT特殊文字效果,TextView实现

事情是这样的,我无聊刷到一个B站视频【旁门左道PPT】我发现了大厂发布会中,少文字PPT还贼高级的秘密!。看到视频中这个特殊的PPT文字效果,个人感觉非常高端。我就想,能不能用TextView来实现。于是就有了这篇文章,效果如下图:

















简单填充加入文字排版加入动画

图片填充


在Android中,google提供了 BitmapShader 来实现图片填充的功能。代码如下


public BitmapShader(@NonNull Bitmap bitmap, 
@NonNull TileMode tileX,
@NonNull TileMode tileY)

参数介绍:


● bitmap:用来做填充的 Bitmap 对象


● tileX:横向的 TileMode(平铺模式)


● tileY:纵向的 TileMode


TileMode有三种:分别是 Shader.TileMode.CLAMP、Shader.TileMode.MIRROR、Shader.TileMode.REPEAT


● Shader.TileMode.CLAMP:如果着色器超出原始边界范围,会复制边缘颜色。


● Shader.TileMode.MIRROR:横向和纵向的重复着色器的图像,交替镜像图像是相邻的图像总是接合。


● Shader.TileMode.REPEAT: 横向和纵向的重复着色器的图像。


接下来,我们自定义 TextView,让它使用我们定义的Shader,代码如下:


class MaskTextView: androidx.appcompat.widget.AppCompatTextView {

constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)

private var shader: BitmapShader? = null

fun setMaskDrawable(source: Drawable): Unit {
val maskW: Int = source.getIntrinsicWidth()
val maskH: Int = source.getIntrinsicHeight()

val b = Bitmap.createBitmap(maskW, maskH, Bitmap.Config.ARGB_8888)
val c = Canvas(b)

c.drawColor(currentTextColor)
source.setBounds(0, 0, maskW, maskH)
source.draw(c)

shader = BitmapShader(b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP)
paint.shader = shader
}
}

免费壁纸网站中找到一个你喜欢的图片,调用 setMaskDrawable 方法时,我们就可以看到填充后的效果了。效果如下:



但是光这个效果还不够,还需要设置文字排版。看【旁门左道PPT】我发现了大厂发布会中,少文字PPT还贼高级的秘密!我们知道,有三种文字排版,分别是 高低低高、高低高低、低高低高,它们都需要修改文字的 baseline 来实现。


如何修改单个字符的 baseline 呢?很简单,不需要重写 onDraw 方法。我们可以自定义 Span,然后通过 TextPaint 来实现。在上代码前,先介绍一下 TextPaint,TextPaint 继承 Paint,在绘制和测量文本时给Android一些额外的数据。它的属性介绍如下:


● baselineShift - 基线是文本底部的线。改变baselineShift会使基线向上或向下移动,所以它影响到文本在一条线上的绘制高度。


● bgColor - 这是文本后面的背景颜色。


● density - 暂不清楚它的作用


● drawableState - 暂不清楚它的作用


● linkColor - 一个链接的文本颜色。


可以看到我们只需要修改 baselineShift 就可以改变单个文字的 baseline 了,自定义的Span的代码如下:


class TextUpOrDownSpan(private val isUp:Boolean, private val offset: Int): CharacterStyle() {

override fun updateDrawState(tp: TextPaint?) {
tp?.baselineShift = if(isUp) - offset else offset
}
}

效果如下:



添加一个波浪动画


我们也可以给我们的图片填充增加一个动画,其中最常见的就是波浪动画了。效果实现很简单:


第一步:在波浪效果网站上下载一张自己想要的波浪图片



第二步:创建自定义的TextView,加上对应的参数,方便做动画。代码如下:


class AnimatorMaskTextView: androidx.appcompat.widget.AppCompatTextView {

private var shader: BitmapShader? = null
private var shaderMatrix: Matrix = Matrix()
private var offsetY = 0f
var maskX = 0f
set(value) {
field = value
invalidate()
}
var maskY = 0f
set(value) {
field = value
invalidate()
}

fun setMaskDrawable(source: Drawable): Unit {
val maskW: Int = source.getIntrinsicWidth()
val maskH: Int = source.getIntrinsicHeight()

val b = Bitmap.createBitmap(maskW, maskH, Bitmap.Config.ARGB_8888)
val c = Canvas(b)

c.drawColor(currentTextColor)
source.setBounds(0, 0, maskW, maskH)
source.draw(c)

shader = BitmapShader(b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP)
paint.shader = shader
offsetY = ((height - maskH) / 2).toFloat()
}

override fun onDraw(canvas: Canvas?) {
shaderMatrix.setTranslate(maskX, offsetY + maskY)
shader?.setLocalMatrix(shaderMatrix)
paint.shader = shader
super.onDraw(canvas)
}
}

第三步:使用Android的动画api,控制图片的位置。代码如下:


val maskXAnimator: ObjectAnimator = 
ObjectAnimator.ofFloat(textView, "maskX", 0f, textView.width.toFloat())
val maskYAnimator: ObjectAnimator =
ObjectAnimator.ofFloat(textView, "maskY", 0f, (-textView.getHeight()).toFloat())
val animatorSet = AnimatorSet()
animatorSet.playTogether(maskXAnimator, maskYAnimator)
animatorSet.start()

效果如下:



作者:小墙程序员
链接:https://juejin.cn/post/7212418415976529981
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册