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