Android 自定义view之TextInputLayout

一.使用EditText实现TextInputLayout

1.1效果


MaterialEditText.gif

1.2 talk is cheap

import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;

import com.example.rookie.hencoder_plus.R;
import com.example.rookie.hencoder_plus.custom_view_06.Utils;

/**
 * 带有提示的EditText
 * 类似于design包中的TextInputLayout
 * 1.加大paddingTop(文字高度+间距)用来摆放hintText
 * 2.文字变化(有->无,无->有)时,增加动画效果
 * 3.增加xml自定义属性以及java代码的开关
 */
public class MaterialEditText extends AppCompatEditText {
    private static final float HINT_TEXT_ANIMATION_OFFSET = Utils.dp2px(25);//动画距离
    private static final float EXTRA_PADDING_TOP_DISTANCE = Utils.dp2px(12);//文字高度
    private static final float EXTRA_MARGIN_TOP_DISTANCE = Utils.dp2px(10);//hint文字距editText高度
    private static final float EXTRA_VERTICAL_OFFSET_ORIGINAL = EXTRA_PADDING_TOP_DISTANCE + EXTRA_MARGIN_TOP_DISTANCE;
    private static final float EXTRA_HORIZONTAL_OFFSET = Utils.dp2px(4);//横向偏移,为了与EditText的content对齐
    TextPaint hintTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    private String hintText = getHint().toString();
    private ObjectAnimator showHintUpAnimator, disappearHintDownAnimator;
    private boolean hintHasShown;//hintText是否已经显示
    private boolean shouldShowTopHint = true;//是否需要显示上面的hint(给外部开发者调用)
    private TextWatcher watcher;

    public MaterialEditText(Context context) {
        this(context, null);
    }

    public MaterialEditText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MaterialEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaterialEditText);
        shouldShowTopHint = typedArray.getBoolean(R.styleable.MaterialEditText_shouldShowTopHint, true);
        typedArray.recycle();
        init();
    }

    private void init() {

        initTextPaint();
        initPadding();
        initTextWatcher();
    }

    private void initTextWatcher() {
        if (!shouldShowTopHint) {
            removeTextChangedListener(watcher);
            return;
        }
        if (watcher == null) {
            watcher = new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (hintHasShown && TextUtils.isEmpty(s)) {
                        //如果已经显示并且EditText已经清空
                        hintHasShown = false;
                        getAnimatorToDisappearDownHint().start();
                    } else if (!hintHasShown && !TextUtils.isEmpty(s.toString())) {
                        //上方的hint还未显示,并且EditText的文字非空
                        hintHasShown = true;
                        getAnimatorToShowUpHint().start();
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            };
            Log.e("test", "看看加了几次");
            addTextChangedListener(watcher);
        }

    }


    ObjectAnimator getAnimatorToShowUpHint() {
        if (showHintUpAnimator == null) {
            showHintUpAnimator = ObjectAnimator.ofFloat(this, "hintFraction", 0, 1);
            showHintUpAnimator.setDuration(1000);
        }
        return showHintUpAnimator;
    }

    ObjectAnimator getAnimatorToDisappearDownHint() {
        if (disappearHintDownAnimator == null) {
            disappearHintDownAnimator = ObjectAnimator.ofFloat(this, "hintFraction", 1, 0);
            disappearHintDownAnimator.setDuration(1000);
        }
        return disappearHintDownAnimator;
    }

    private void initPadding() {
        //增大paddingtop,为hinttext腾地方
        int paddingTop = shouldShowTopHint ? (int) (getPaddingTop() + EXTRA_VERTICAL_OFFSET_ORIGINAL) : (int) (getPaddingTop() - EXTRA_VERTICAL_OFFSET_ORIGINAL);
        setPadding(getPaddingLeft(), paddingTop, getPaddingRight(), getPaddingBottom());
    }

    private void initTextPaint() {
        hintTextPaint.setColor(Color.BLACK);
        hintTextPaint.setTextSize(EXTRA_PADDING_TOP_DISTANCE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //通过动画的fraction配合paint的alpha来实现文字的显示和消失
        hintTextPaint.setAlpha((int) (0xff * hintFraction));
        canvas.drawText(hintText, EXTRA_HORIZONTAL_OFFSET, EXTRA_PADDING_TOP_DISTANCE + HINT_TEXT_ANIMATION_OFFSET * (1 - hintFraction), hintTextPaint);
    }

    /* 属性动画使用start */
    private float hintFraction;

    public float getHintFraction() {
        return hintFraction;
    }

    /**
     * dont  call this method from outside
     *
     * @param hintFraction
     */
    public void setHintFraction(float hintFraction) {
        this.hintFraction = hintFraction;
        invalidate();
    }
    /* 属性动画使用end */

    public void setShouldShowTopHint(boolean shouldShowTopHint) {
        if (this.shouldShowTopHint != shouldShowTopHint) {
            //如果当前显示的flag和传入的flag不同时,才修改状态
            //1。修改padding
            if (this.shouldShowTopHint) {
                //原来显示,变为不显示,则去掉padding
            } else {
                //原来不显示,变为显示,加上padding
            }
            this.shouldShowTopHint = shouldShowTopHint;
            initPadding();
            initTextWatcher();
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容