package com.material.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.EditText;
/**
* Created by IntelliJ IDEA.
* User: keith.
* Date: 14-10-30.
* Time: 15:57.
*/
public class FloatingEditText extends EditText {
private static final long ANIMATION_DURATION = 120;
private static final int StateHintNormal = 0;
private static final int StateHintZoomIn = 1;
private static final int StateHintZoomOut = 2;
private static final float HINT_SCALE = 0.5f;
private int mState = StateHintNormal;
private long mStartTime;
private int mColor;
private int mHighlightedColor;
private int mErrorColor;
private boolean mVerified = true;
private String mValidateMessage;
private int mUnderlineHeight;
private int mUnderlineHighlightedHeight;
private boolean mTextEmpty;
private float mHintScale;
private Rect lineRect = new Rect();
private Paint mHintPaint;
public FloatingEditText(Context context) {
this(context, null);
}
public FloatingEditText(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.editTextStyle);
}
public FloatingEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, android.R.attr.editTextStyle);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.FloatingEditText);
mHintScale = attributes.getFloat(R.styleable.FloatingEditText_floating_edit_text_hint_scale,
HINT_SCALE);
mColor = attributes.getColor(R.styleable.FloatingEditText_floating_edit_text_color,
getResources().getColor(R.color.floating_edit_text_color));
mHighlightedColor = attributes.getColor(R.styleable.FloatingEditText_floating_edit_text_highlighted_color,
getResources().getColor(R.color.floating_edit_text_highlighted_color));
mErrorColor = attributes.getColor(R.styleable.FloatingEditText_floating_edit_text_error_color,
getResources().getColor(R.color.floating_edit_text_error_color));
mUnderlineHeight = attributes.getDimensionPixelSize(R.styleable.FloatingEditText_floating_edit_text_underline_height,
getResources().getDimensionPixelSize(R.dimen.floating_edit_text_underline_height));
mUnderlineHighlightedHeight = attributes.getDimensionPixelSize(R.styleable.FloatingEditText_floating_edit_text_underline_highlighted_height,
getResources().getDimensionPixelSize(R.dimen.floating_edit_text_underline_highlighted_height));
setHintTextColor(Color.TRANSPARENT);
mTextEmpty = TextUtils.isEmpty(getText());
mHintPaint = new Paint();
mHintPaint.setAntiAlias(true);
Drawable drawable = new Drawable() {
@Override
public void draw(Canvas canvas) {
if (mVerified) {
if (isFocused()) {
Rect rect = getThickLineRect(canvas);
mHintPaint.setColor(mHighlightedColor);
canvas.drawRect(rect, mHintPaint);
} else {
Rect rect = getThinLineRect(canvas);
mHintPaint.setColor(mColor);
canvas.drawRect(rect, mHintPaint);
}
} else {
Rect rect = getThickLineRect(canvas);
mHintPaint.setColor(mErrorColor);
canvas.drawRect(rect, mHintPaint);
mHintPaint.setColor(mErrorColor);
mHintPaint.setTextSize(getTextSize() * 0.6f);
float x = getCompoundPaddingLeft();
float y = rect.bottom + (dpToPx(16) - mHintPaint.getFontMetricsInt().top) / 2;
canvas.drawText(mValidateMessage, x, y, mHintPaint);
}
}
@Override
public void setAlpha(int alpha) {
mHintPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mHintPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSPARENT;
}
};
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
setBackgroundDrawable(drawable);
} else {
setBackground(drawable);
}
int paddingTop = dpToPx(12);
int paddingBottom = dpToPx(20);
setPadding(0, paddingTop, 0, paddingBottom);
}
private Rect getThinLineRect(Canvas canvas) {
lineRect.left = getPaddingLeft();
lineRect.top = canvas.getHeight() - mUnderlineHeight - dpToPx(16);
lineRect.right = getWidth();
lineRect.bottom = canvas.getHeight() - dpToPx(16);
return lineRect;
}
private Rect getThickLineRect(Canvas canvas) {
lineRect.left = getPaddingLeft();
lineRect.top = canvas.getHeight() - mUnderlineHighlightedHeight - dpToPx(16);
lineRect.right = getWidth();
lineRect.bottom = canvas.getHeight() - dpToPx(16);
return lineRect;
}
public void setNormalColor(int color) {
this.mColor = color;
invalidate();
}
public void setHighlightedColor(int color) {
this.mHighlightedColor = color;
invalidate();
}
public void setValidateResult(boolean verified, String message) {
if (!verified && message == null) {
throw new IllegalStateException("Must have a validate result message.");
}
this.mVerified = verified;
this.mValidateMessage = message;
invalidate();
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
this.mVerified = true;
this.mValidateMessage = null;
boolean isEmpty = TextUtils.isEmpty(getText());
if (mTextEmpty != isEmpty) {
this.mTextEmpty = isEmpty;
if (isEmpty && isShown()) {
mStartTime = System.currentTimeMillis();
mState = StateHintZoomIn;
} else {
mStartTime = System.currentTimeMillis();
mState = StateHintZoomOut;
}
}
}
@Override
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
if (!TextUtils.isEmpty(getHint())) {
mHintPaint.set(getPaint());
float maxTextSize = getTextSize();
float minTextSize = getTextSize() * mHintScale;
float maxHintY = getBaseline();
float minHintY = getBaseline() + getPaint().getFontMetricsInt().top + getScrollY() - dpToPx(4);
float textSize;
float hintY;
float hintX = getCompoundPaddingLeft() + getScrollX();
long elapsed = System.currentTimeMillis() - mStartTime;
switch (mState) {
case StateHintNormal: {
textSize = maxTextSize;
hintY = maxHintY;
mHintPaint.setColor(mColor);
mHintPaint.setTextSize(textSize);
canvas.drawText(getHint().toString(), hintX, hintY, mHintPaint);
}
break;
case StateHintZoomIn: {
if (elapsed < ANIMATION_DURATION) {
textSize = ((maxTextSize - minTextSize) * elapsed) / ANIMATION_DURATION + minTextSize;
hintY = ((maxHintY - minHintY) * elapsed) / ANIMATION_DURATION + minHintY;
mHintPaint.setColor(mHighlightedColor);
mHintPaint.setTextSize(textSize);
canvas.drawText(getHint().toString(), hintX, hintY, mHintPaint);
postInvalidate();
} else {
textSize = maxTextSize;
hintY = maxHintY;
mHintPaint.setColor(mColor);
mHintPaint.setTextSize(textSize);
canvas.drawText(getHint().toString(), hintX, hintY, mHintPaint);
}
}
break;
case StateHintZoomOut: {
if (elapsed < ANIMATION_DURATION) {
textSize = maxTextSize - ((maxTextSize - minTextSize) * elapsed) / ANIMATION_DURATION;
hintY = maxHintY - ((maxHintY - minHintY) * elapsed) / ANIMATION_DURATION;
mHintPaint.setColor(mHighlightedColor);
mHintPaint.setTextSize(textSize);
canvas.drawText(getHint().toString(), hintX, hintY, mHintPaint);
postInvalidate();
} else {
textSize = minTextSize;
hintY = minHintY;
if (isFocused()) {
mHintPaint.setColor(mHighlightedColor);
} else {
mHintPaint.setColor(mColor);
}
mHintPaint.setTextSize(textSize);
canvas.drawText(getHint().toString(), hintX, hintY, mHintPaint);
}
}
break;
}
}
}
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
}