自定义MaterialEditText

自定义MaterialEditText

日记

现在都不流行写博客了,因为这玩意都认为对于面试没啥用,我感觉很多事情不应该太功利。所谓博客还是更多的应该用来进行自己日常学习的归纳和总结,而不是去贪图所谓的面试加分。因为面试可能是一时的,但是自己实际是否掌握了,那就是长久的。

今天晚上就更新啦,哈哈哈哈,期待期待。

前言

一如既往,这是我日常学习的日记,最近在巩固一些基础东西,总感觉一些Android基础还是偏薄弱。所以还是打算从基础重新来一遍,真的,很多时候,很多问题出现的原因并不是顶层的原因,而是我们从根本,从基础上就不牢靠。最近闲下来就在看扔物线的视频,说真的,很多其实挺基础的,但是感觉能在基础上面翻出花样来其实也是一种本事。因此,来讲讲今天的主题自定义MaterialEditText。

当然,我并不打算完整地实现一摸一样的一个相同库出来,如果是那样,那就完蛋了。今天就选一个最简单的案例来讲讲吧。就当是前面几讲的归纳和总结了。

正文

我们需要实现的目标效果如下:没有输入文字的时候EditText显示的是Hint的提示信息,当输入文字之后,EditText显示的是实际输入的文字信息,同时Label从下到上,从浅变深显示Label。
自定义MaterialEditText_第1张图片

来整体规划一下思路,我们只需要重点关注上面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文字的动画。重点关注onTextChangedonDraw这两个方法。整体思路是在onTextChanged方法回调中判断文字变化前的长度和文字变化后的长度。

  1. 文字从无变有,hint标题栏逐渐上浮,透明度从全透明到纯色
  2. 文字从有变无,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()
        }
    }

}


你可能感兴趣的:(android,kotlin,动画)