自定义MaterialEditText
日记
现在都不流行写博客了,因为这玩意都认为对于面试没啥用,我感觉很多事情不应该太功利。所谓博客还是更多的应该用来进行自己日常学习的归纳和总结,而不是去贪图所谓的面试加分。因为面试可能是一时的,但是自己实际是否掌握了,那就是长久的。
今天晚上就更新啦,哈哈哈哈,期待期待。
前言
一如既往,这是我日常学习的日记,最近在巩固一些基础东西,总感觉一些Android基础还是偏薄弱。所以还是打算从基础重新来一遍,真的,很多时候,很多问题出现的原因并不是顶层的原因,而是我们从根本,从基础上就不牢靠。最近闲下来就在看扔物线的视频,说真的,很多其实挺基础的,但是感觉能在基础上面翻出花样来其实也是一种本事。因此,来讲讲今天的主题自定义MaterialEditText。
当然,我并不打算完整地实现一摸一样的一个相同库出来,如果是那样,那就完蛋了。今天就选一个最简单的案例来讲讲吧。就当是前面几讲的归纳和总结了。
正文
我们需要实现的目标效果如下:没有输入文字的时候EditText显示的是Hint的提示信息,当输入文字之后,EditText显示的是实际输入的文字信息,同时Label从下到上,从浅变深显示Label。
来整体规划一下思路,我们只需要重点关注上面Label的显示状态的变化即可,Label的变化说到底仅仅是一个属性动画。我们需要在Draw的时候,根据动画进度,来动态地进行绘制即可。
首先,我们先绘制输入完成后地文本样式:总体就是上下结构,上面是一行文本,下面是可输入的文本框。这个很简单,首先,在视图定义的时候设置视图高度为wrap_content,然后在视图初始化的时候修改视图的padding从而给hint提示文本让出对应的空间即可。
//Hint栏距离顶端距离,单纯为了美观
val MARGIN_TOP = 20.dp
init {
//设置初始间距
setPadding(
paddingLeft,
//给hint文本绘制空出对应的位置
(paddingTop + MARGIN_TOP + textSize).toInt(),
paddingRight,
paddingBottom
)
paint.textSize = textSize
}
位置空好了,我们来绘制对应的Hint文本。因为是Demo,我们就设计的简单一点,不专门给hint设置什么特别的文字样式了,除了文字大之外的其他值就直接使用默认值就行了。
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawText(
hint.toString(),
paddingLeft.toFloat(),
textSize + MARGIN_TOP,
paint
)
}
接下来,我们就要在文字长度产生变化的时候触发对于Hint文字的动画。重点关注onTextChanged
和onDraw
这两个方法。整体思路是在onTextChanged
方法回调中判断文字变化前的长度和文字变化后的长度。
- 文字从无变有,hint标题栏逐渐上浮,透明度从全透明到纯色
- 文字从有变无,hint标题栏逐渐下沉,透明度从纯色到全透明
我们在自定义MaterialEditText中定义一个局部变量fraction来作为属性动画的操作对象,在onDraw方法中根据fraction局部变量来动态的控制Hint标题栏的透明度和动态位置。
来看看具体的实现吧。
/**
* 自定义EditText
*/
//Hint栏距离顶端距离
val MARGIN_TOP = 20.dp
class MaterialEditText(context: Context, attributeSet: AttributeSet) :
AppCompatEditText(context, attributeSet) {
//动画执行进度
var fraction = 1f
set(value) {
field = value
invalidate()
}
var supportLabel = false
private val offsetAnimator: ObjectAnimator by lazy {
ObjectAnimator.ofFloat(this, "fraction", 0f, 1f).apply { duration = 1000 }
}
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
init {
val materialEditTextAttrs =
context.obtainStyledAttributes(attributeSet, R.styleable.MaterialEditText)
supportLabel =
materialEditTextAttrs.getBoolean(R.styleable.MaterialEditText_support_label, false)
materialEditTextAttrs.recycle()
if (supportLabel) {
//设置初始间距
setPadding(
paddingLeft,
(paddingTop + MARGIN_TOP + textSize).toInt(),
paddingRight,
paddingBottom
)
paint.textSize = textSize
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if(!supportLabel)return
paint.alpha = ((1 - fraction) * 255).toInt()
canvas.drawText(
hint.toString(),
paddingLeft.toFloat(),
textSize + MARGIN_TOP + textSize * fraction,
paint
)
}
override fun onTextChanged(
text: CharSequence?,
start: Int,
lengthBefore: Int,
lengthAfter: Int
) {
super.onTextChanged(text, start, lengthBefore, lengthAfter)
if(!supportLabel) return
if (text.isNullOrEmpty() && lengthBefore > 0) {
offsetAnimator.start()
} else if (lengthBefore <= 0 && lengthAfter > 0) {
offsetAnimator.reverse()
}
}
}