美文网首页
Android 自定义view之TextInputLayout

Android 自定义view之TextInputLayout

作者: RookieRun | 来源:发表于2020-04-09 22:47 被阅读0次

    一.使用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();
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Android 自定义view之TextInputLayout

          本文链接:https://www.haomeiwen.com/subject/fndkmhtx.html