diff --git a/library/src/main/java/com/rengwuxian/materialedittext/MaterialEditText.java b/library/src/main/java/com/rengwuxian/materialedittext/MaterialEditText.java
index edfbcf1e..7d617129 100755
--- a/library/src/main/java/com/rengwuxian/materialedittext/MaterialEditText.java
+++ b/library/src/main/java/com/rengwuxian/materialedittext/MaterialEditText.java
@@ -50,1479 +50,1501 @@
  */
 public class MaterialEditText extends MaterialBaseEditText {
 
-  @IntDef({FLOATING_LABEL_NONE, FLOATING_LABEL_NORMAL, FLOATING_LABEL_HIGHLIGHT})
-  public @interface FloatingLabelType {
-  }
-
-  public static final int FLOATING_LABEL_NONE = 0;
-  public static final int FLOATING_LABEL_NORMAL = 1;
-  public static final int FLOATING_LABEL_HIGHLIGHT = 2;
-
-  /**
-   * the spacing between the main text and the inner top padding.
-   */
-  private int extraPaddingTop;
-
-  /**
-   * the spacing between the main text and the inner bottom padding.
-   */
-  private int extraPaddingBottom;
-
-  /**
-   * the extra spacing between the main text and the left, actually for the left icon.
-   */
-  private int extraPaddingLeft;
-
-  /**
-   * the extra spacing between the main text and the right, actually for the right icon.
-   */
-  private int extraPaddingRight;
-
-  /**
-   * the floating label's text size.
-   */
-  private int floatingLabelTextSize;
-
-  /**
-   * the floating label's text color.
-   */
-  private int floatingLabelTextColor;
-
-  /**
-   * the bottom texts' size.
-   */
-  private int bottomTextSize;
-
-  /**
-   * the spacing between the main text and the floating label.
-   */
-  private int floatingLabelPadding;
-
-  /**
-   * the spacing between the main text and the bottom components (bottom ellipsis, helper/error text, characters counter).
-   */
-  private int bottomSpacing;
-
-  /**
-   * whether the floating label should be shown. default is false.
-   */
-  private boolean floatingLabelEnabled;
-
-  /**
-   * whether to highlight the floating label's text color when focused (with the main color). default is true.
-   */
-  private boolean highlightFloatingLabel;
-
-  /**
-   * the base color of the line and the texts. default is black.
-   */
-  private int baseColor;
-
-  /**
-   * inner top padding
-   */
-  private int innerPaddingTop;
-
-  /**
-   * inner bottom padding
-   */
-  private int innerPaddingBottom;
-
-  /**
-   * inner left padding
-   */
-  private int innerPaddingLeft;
-
-  /**
-   * inner right padding
-   */
-  private int innerPaddingRight;
-
-  /**
-   * the underline's highlight color, and the highlight color of the floating label if app:highlightFloatingLabel is set true in the xml. default is black(when app:darkTheme is false) or white(when app:darkTheme is true)
-   */
-  private int primaryColor;
-
-  /**
-   * the color for when something is wrong.(e.g. exceeding max characters)
-   */
-  private int errorColor;
-
-  /**
-   * min characters count limit. 0 means no limit. default is 0. NOTE: the character counter will increase the View's height.
-   */
-  private int minCharacters;
-
-  /**
-   * max characters count limit. 0 means no limit. default is 0. NOTE: the character counter will increase the View's height.
-   */
-  private int maxCharacters;
-
-  /**
-   * whether to show the bottom ellipsis in singleLine mode. default is false. NOTE: the bottom ellipsis will increase the View's height.
-   */
-  private boolean singleLineEllipsis;
-
-  /**
-   * Always show the floating label, instead of animating it in/out. False by default.
-   */
-  private boolean floatingLabelAlwaysShown;
-
-  /**
-   * Always show the helper text, no matter if the edit text is focused. False by default.
-   */
-  private boolean helperTextAlwaysShown;
-
-  /**
-   * bottom ellipsis's height
-   */
-  private int bottomEllipsisSize;
-
-  /**
-   * min bottom lines count.
-   */
-  private int minBottomLines;
-
-  /**
-   * reserved bottom text lines count, no matter if there is some helper/error text.
-   */
-  private int minBottomTextLines;
-
-  /**
-   * real-time bottom lines count. used for bottom extending/collapsing animation.
-   */
-  private float currentBottomLines;
-
-  /**
-   * bottom lines count.
-   */
-  private float bottomLines;
-
-  /**
-   * Helper text at the bottom
-   */
-  private String helperText;
-
-  /**
-   * Helper text color
-   */
-  private int helperTextColor = -1;
-
-  /**
-   * error text for manually invoked {@link #setError(CharSequence)}
-   */
-  private String tempErrorText;
-
-  /**
-   * animation fraction of the floating label (0 as totally hidden).
-   */
-  private float floatingLabelFraction;
-
-  /**
-   * whether the floating label is being shown.
-   */
-  private boolean floatingLabelShown;
-
-  /**
-   * the floating label's focusFraction
-   */
-  private float focusFraction;
-
-  /**
-   * The font used for the accent texts (floating label, error/helper text, character counter, etc.)
-   */
-  private Typeface accentTypeface;
-
-  /**
-   * The font used on the view (EditText content)
-   */
-  private Typeface typeface;
-
-  /**
-   * Text for the floatLabel if different from the hint
-   */
-  private CharSequence floatingLabelText;
-
-  /**
-   * Whether or not to show the underline. Shown by default
-   */
-  private boolean hideUnderline;
-
-  /**
-   * Underline's color
-   */
-  private int underlineColor;
-
-  /**
-   * Whether to validate as soon as the text has changed. False by default
-   */
-  private boolean autoValidate;
-
-  /**
-   * Whether the characters count is valid
-   */
-  private boolean charactersCountValid;
-
-  /**
-   * Whether use animation to show/hide the floating label.
-   */
-  private boolean floatingLabelAnimating;
-
-  /**
-   * Whether check the characters count at the beginning it's shown.
-   */
-  private boolean checkCharactersCountAtBeginning;
-
-  /**
-   * Left Icon
-   */
-  private Bitmap[] iconLeftBitmaps;
-
-  /**
-   * Right Icon
-   */
-  private Bitmap[] iconRightBitmaps;
-
-  /**
-   * Clear Button
-   */
-  private Bitmap[] clearButtonBitmaps;
-
-  /**
-   * Auto validate when focus lost.
-   */
-  private boolean validateOnFocusLost;
-
-  private boolean showClearButton;
-  private boolean firstShown;
-  private int iconSize;
-  private int iconOuterWidth;
-  private int iconOuterHeight;
-  private int iconPadding;
-  private boolean clearButtonTouched;
-  private boolean clearButtonClicking;
-  private ColorStateList textColorStateList;
-  private ColorStateList textColorHintStateList;
-  private ArgbEvaluator focusEvaluator = new ArgbEvaluator();
-  Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
-  TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
-  StaticLayout textLayout;
-  ObjectAnimator labelAnimator;
-  ObjectAnimator labelFocusAnimator;
-  ObjectAnimator bottomLinesAnimator;
-  OnFocusChangeListener innerFocusChangeListener;
-  OnFocusChangeListener outerFocusChangeListener;
-  private List<METValidator> validators;
-  private METLengthChecker lengthChecker;
-
-  public MaterialEditText(Context context) {
-    super(context);
-    init(context, null);
-  }
-
-  public MaterialEditText(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    init(context, attrs);
-  }
-
-  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-  public MaterialEditText(Context context, AttributeSet attrs, int style) {
-    super(context, attrs, style);
-    init(context, attrs);
-  }
-
-  private void init(Context context, AttributeSet attrs) {
-    if (isInEditMode()) {
-        return;
-    }
-
-    iconSize = getPixel(32);
-    iconOuterWidth = getPixel(48);
-    iconOuterHeight = getPixel(32);
-
-    bottomSpacing = getResources().getDimensionPixelSize(R.dimen.inner_components_spacing);
-    bottomEllipsisSize = getResources().getDimensionPixelSize(R.dimen.bottom_ellipsis_height);
-
-    // default baseColor is black
-    int defaultBaseColor = Color.BLACK;
-
-    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaterialEditText);
-    textColorStateList = typedArray.getColorStateList(R.styleable.MaterialEditText_met_textColor);
-    textColorHintStateList = typedArray.getColorStateList(R.styleable.MaterialEditText_met_textColorHint);
-    baseColor = typedArray.getColor(R.styleable.MaterialEditText_met_baseColor, defaultBaseColor);
-
-    // retrieve the default primaryColor
-    int defaultPrimaryColor;
-    TypedValue primaryColorTypedValue = new TypedValue();
-    try {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-        context.getTheme().resolveAttribute(android.R.attr.colorPrimary, primaryColorTypedValue, true);
-        defaultPrimaryColor = primaryColorTypedValue.data;
-      } else {
-        throw new RuntimeException("SDK_INT less than LOLLIPOP");
-      }
-    } catch (Exception e) {
-      try {
-        int colorPrimaryId = getResources().getIdentifier("colorPrimary", "attr", getContext().getPackageName());
-        if (colorPrimaryId != 0) {
-          context.getTheme().resolveAttribute(colorPrimaryId, primaryColorTypedValue, true);
-          defaultPrimaryColor = primaryColorTypedValue.data;
+    @IntDef({FLOATING_LABEL_NONE, FLOATING_LABEL_NORMAL, FLOATING_LABEL_HIGHLIGHT})
+    public @interface FloatingLabelType {
+    }
+
+    public static final int FLOATING_LABEL_NONE = 0;
+    public static final int FLOATING_LABEL_NORMAL = 1;
+    public static final int FLOATING_LABEL_HIGHLIGHT = 2;
+
+    /**
+     * the color for the disabled dotted underline.
+     */
+    private int disabledUnderlineColor;
+
+    /**
+     * the spacing between the main text and the inner top padding.
+     */
+    private int extraPaddingTop;
+
+    /**
+     * the spacing between the main text and the inner bottom padding.
+     */
+    private int extraPaddingBottom;
+
+    /**
+     * the extra spacing between the main text and the left, actually for the left icon.
+     */
+    private int extraPaddingLeft;
+
+    /**
+     * the extra spacing between the main text and the right, actually for the right icon.
+     */
+    private int extraPaddingRight;
+
+    /**
+     * the floating label's text size.
+     */
+    private int floatingLabelTextSize;
+
+    /**
+     * the floating label's text color.
+     */
+    private int floatingLabelTextColor;
+
+    /**
+     * the bottom texts' size.
+     */
+    private int bottomTextSize;
+
+    /**
+     * the spacing between the main text and the floating label.
+     */
+    private int floatingLabelPadding;
+
+    /**
+     * the spacing between the main text and the bottom components (bottom ellipsis, helper/error text, characters counter).
+     */
+    private int bottomSpacing;
+
+    /**
+     * whether the floating label should be shown. default is false.
+     */
+    private boolean floatingLabelEnabled;
+
+    /**
+     * whether to highlight the floating label's text color when focused (with the main color). default is true.
+     */
+    private boolean highlightFloatingLabel;
+
+    /**
+     * the base color of the line and the texts. default is black.
+     */
+    private int baseColor;
+
+    /**
+     * inner top padding
+     */
+    private int innerPaddingTop;
+
+    /**
+     * inner bottom padding
+     */
+    private int innerPaddingBottom;
+
+    /**
+     * inner left padding
+     */
+    private int innerPaddingLeft;
+
+    /**
+     * inner right padding
+     */
+    private int innerPaddingRight;
+
+    /**
+     * the underline's highlight color, and the highlight color of the floating label if app:highlightFloatingLabel is set true in the xml. default is black(when app:darkTheme is false) or white(when app:darkTheme is true)
+     */
+    private int primaryColor;
+
+    /**
+     * the color for when something is wrong.(e.g. exceeding max characters)
+     */
+    private int errorColor;
+
+    /**
+     * min characters count limit. 0 means no limit. default is 0. NOTE: the character counter will increase the View's height.
+     */
+    private int minCharacters;
+
+    /**
+     * max characters count limit. 0 means no limit. default is 0. NOTE: the character counter will increase the View's height.
+     */
+    private int maxCharacters;
+
+    /**
+     * whether to show the bottom ellipsis in singleLine mode. default is false. NOTE: the bottom ellipsis will increase the View's height.
+     */
+    private boolean singleLineEllipsis;
+
+    /**
+     * Always show the floating label, instead of animating it in/out. False by default.
+     */
+    private boolean floatingLabelAlwaysShown;
+
+    /**
+     * Always show the helper text, no matter if the edit text is focused. False by default.
+     */
+    private boolean helperTextAlwaysShown;
+
+    /**
+     * bottom ellipsis's height
+     */
+    private int bottomEllipsisSize;
+
+    /**
+     * min bottom lines count.
+     */
+    private int minBottomLines;
+
+    /**
+     * reserved bottom text lines count, no matter if there is some helper/error text.
+     */
+    private int minBottomTextLines;
+
+    /**
+     * real-time bottom lines count. used for bottom extending/collapsing animation.
+     */
+    private float currentBottomLines;
+
+    /**
+     * bottom lines count.
+     */
+    private float bottomLines;
+
+    /**
+     * Helper text at the bottom
+     */
+    private String helperText;
+
+    /**
+     * Helper text color
+     */
+    private int helperTextColor = -1;
+
+    /**
+     * error text for manually invoked {@link #setError(CharSequence)}
+     */
+    private String tempErrorText;
+
+    /**
+     * animation fraction of the floating label (0 as totally hidden).
+     */
+    private float floatingLabelFraction;
+
+    /**
+     * whether the floating label is being shown.
+     */
+    private boolean floatingLabelShown;
+
+    /**
+     * the floating label's focusFraction
+     */
+    private float focusFraction;
+
+    /**
+     * The font used for the accent texts (floating label, error/helper text, character counter, etc.)
+     */
+    private Typeface accentTypeface;
+
+    /**
+     * The font used on the view (EditText content)
+     */
+    private Typeface typeface;
+
+    /**
+     * Text for the floatLabel if different from the hint
+     */
+    private CharSequence floatingLabelText;
+
+    /**
+     * Whether or not to show the underline. Shown by default
+     */
+    private boolean hideUnderline;
+
+    /**
+     * Underline's color
+     */
+    private int underlineColor;
+
+    /**
+     * Whether to validate as soon as the text has changed. False by default
+     */
+    private boolean autoValidate;
+
+    /**
+     * Whether the characters count is valid
+     */
+    private boolean charactersCountValid;
+
+    /**
+     * Whether use animation to show/hide the floating label.
+     */
+    private boolean floatingLabelAnimating;
+
+    /**
+     * Whether check the characters count at the beginning it's shown.
+     */
+    private boolean checkCharactersCountAtBeginning;
+
+    /**
+     * Left Icon
+     */
+    private Bitmap[] iconLeftBitmaps;
+
+    /**
+     * Right Icon
+     */
+    private Bitmap[] iconRightBitmaps;
+
+    /**
+     * Clear Button
+     */
+    private Bitmap[] clearButtonBitmaps;
+
+    /**
+     * Auto validate when focus lost.
+     */
+    private boolean validateOnFocusLost;
+
+    private boolean showClearButton;
+    private boolean firstShown;
+    private int iconSize;
+    private int iconOuterWidth;
+    private int iconOuterHeight;
+    private int iconPadding;
+    private boolean clearButtonTouched;
+    private boolean clearButtonClicking;
+    private ColorStateList textColorStateList;
+    private ColorStateList textColorHintStateList;
+    private ArgbEvaluator focusEvaluator = new ArgbEvaluator();
+    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+    StaticLayout textLayout;
+    ObjectAnimator labelAnimator;
+    ObjectAnimator labelFocusAnimator;
+    ObjectAnimator bottomLinesAnimator;
+    OnFocusChangeListener innerFocusChangeListener;
+    OnFocusChangeListener outerFocusChangeListener;
+    private List<METValidator> validators;
+    private METLengthChecker lengthChecker;
+    private boolean dottedBottomLinesForDisabledState;
+
+
+    public MaterialEditText(Context context) {
+        super(context);
+        init(context, null);
+    }
+
+    public MaterialEditText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context, attrs);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public MaterialEditText(Context context, AttributeSet attrs, int style) {
+        super(context, attrs, style);
+        init(context, attrs);
+    }
+
+    private void init(Context context, AttributeSet attrs) {
+        if (isInEditMode()) {
+            return;
+        }
+
+        iconSize = getPixel(32);
+        iconOuterWidth = getPixel(48);
+        iconOuterHeight = getPixel(32);
+
+        bottomSpacing = getResources().getDimensionPixelSize(R.dimen.inner_components_spacing);
+        bottomEllipsisSize = getResources().getDimensionPixelSize(R.dimen.bottom_ellipsis_height);
+
+        // default baseColor is black
+        int defaultBaseColor = Color.BLACK;
+
+        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaterialEditText);
+        textColorStateList = typedArray.getColorStateList(R.styleable.MaterialEditText_met_textColor);
+        textColorHintStateList = typedArray.getColorStateList(R.styleable.MaterialEditText_met_textColorHint);
+        baseColor = typedArray.getColor(R.styleable.MaterialEditText_met_baseColor, defaultBaseColor);
+
+        // retrieve the default primaryColor
+        int defaultPrimaryColor;
+        TypedValue primaryColorTypedValue = new TypedValue();
+        try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                context.getTheme().resolveAttribute(android.R.attr.colorPrimary, primaryColorTypedValue, true);
+                defaultPrimaryColor = primaryColorTypedValue.data;
+            } else {
+                throw new RuntimeException("SDK_INT less than LOLLIPOP");
+            }
+        } catch (Exception e) {
+            try {
+                int colorPrimaryId = getResources().getIdentifier("colorPrimary", "attr", getContext().getPackageName());
+                if (colorPrimaryId != 0) {
+                    context.getTheme().resolveAttribute(colorPrimaryId, primaryColorTypedValue, true);
+                    defaultPrimaryColor = primaryColorTypedValue.data;
+                } else {
+                    throw new RuntimeException("colorPrimary not found");
+                }
+            } catch (Exception e1) {
+                defaultPrimaryColor = baseColor;
+            }
+        }
+
+        primaryColor = typedArray.getColor(R.styleable.MaterialEditText_met_primaryColor, defaultPrimaryColor);
+        setFloatingLabelInternal(typedArray.getInt(R.styleable.MaterialEditText_met_floatingLabel, 0));
+        errorColor = typedArray.getColor(R.styleable.MaterialEditText_met_errorColor, Color.parseColor("#e7492E"));
+        disabledUnderlineColor = typedArray.getColor(R.styleable.MaterialEditText_met_disabledBottomLineColor, -1);
+        minCharacters = typedArray.getInt(R.styleable.MaterialEditText_met_minCharacters, 0);
+        maxCharacters = typedArray.getInt(R.styleable.MaterialEditText_met_maxCharacters, 0);
+        dottedBottomLinesForDisabledState = typedArray.getBoolean(R.styleable.MaterialEditText_met_disabledBottomLineDotted, true);
+        singleLineEllipsis = typedArray.getBoolean(R.styleable.MaterialEditText_met_singleLineEllipsis, false);
+        helperText = typedArray.getString(R.styleable.MaterialEditText_met_helperText);
+        helperTextColor = typedArray.getColor(R.styleable.MaterialEditText_met_helperTextColor, -1);
+        minBottomTextLines = typedArray.getInt(R.styleable.MaterialEditText_met_minBottomTextLines, 0);
+        String fontPathForAccent = typedArray.getString(R.styleable.MaterialEditText_met_accentTypeface);
+        if (fontPathForAccent != null && !isInEditMode()) {
+            accentTypeface = getCustomTypeface(fontPathForAccent);
+            textPaint.setTypeface(accentTypeface);
+        }
+        String fontPathForView = typedArray.getString(R.styleable.MaterialEditText_met_typeface);
+        if (fontPathForView != null && !isInEditMode()) {
+            typeface = getCustomTypeface(fontPathForView);
+            setTypeface(typeface);
+        }
+        floatingLabelText = typedArray.getString(R.styleable.MaterialEditText_met_floatingLabelText);
+        if (floatingLabelText == null) {
+            floatingLabelText = getHint();
+        }
+        floatingLabelPadding = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_floatingLabelPadding, bottomSpacing);
+        floatingLabelTextSize = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_floatingLabelTextSize, getResources().getDimensionPixelSize(R.dimen.floating_label_text_size));
+        floatingLabelTextColor = typedArray.getColor(R.styleable.MaterialEditText_met_floatingLabelTextColor, -1);
+        floatingLabelAnimating = typedArray.getBoolean(R.styleable.MaterialEditText_met_floatingLabelAnimating, true);
+        bottomTextSize = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_bottomTextSize, getResources().getDimensionPixelSize(R.dimen.bottom_text_size));
+        hideUnderline = typedArray.getBoolean(R.styleable.MaterialEditText_met_hideUnderline, false);
+        underlineColor = typedArray.getColor(R.styleable.MaterialEditText_met_underlineColor, -1);
+        autoValidate = typedArray.getBoolean(R.styleable.MaterialEditText_met_autoValidate, false);
+        iconLeftBitmaps = generateIconBitmaps(typedArray.getResourceId(R.styleable.MaterialEditText_met_iconLeft, -1));
+        iconRightBitmaps = generateIconBitmaps(typedArray.getResourceId(R.styleable.MaterialEditText_met_iconRight, -1));
+        showClearButton = typedArray.getBoolean(R.styleable.MaterialEditText_met_clearButton, false);
+        clearButtonBitmaps = generateIconBitmaps(R.drawable.met_ic_clear);
+        iconPadding = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_iconPadding, getPixel(16));
+        floatingLabelAlwaysShown = typedArray.getBoolean(R.styleable.MaterialEditText_met_floatingLabelAlwaysShown, false);
+        helperTextAlwaysShown = typedArray.getBoolean(R.styleable.MaterialEditText_met_helperTextAlwaysShown, false);
+        validateOnFocusLost = typedArray.getBoolean(R.styleable.MaterialEditText_met_validateOnFocusLost, false);
+        checkCharactersCountAtBeginning = typedArray.getBoolean(R.styleable.MaterialEditText_met_checkCharactersCountAtBeginning, true);
+        typedArray.recycle();
+
+        int[] paddings = new int[]{
+                android.R.attr.padding, // 0
+                android.R.attr.paddingLeft, // 1
+                android.R.attr.paddingTop, // 2
+                android.R.attr.paddingRight, // 3
+                android.R.attr.paddingBottom // 4
+        };
+        TypedArray paddingsTypedArray = context.obtainStyledAttributes(attrs, paddings);
+        int padding = paddingsTypedArray.getDimensionPixelSize(0, 0);
+        innerPaddingLeft = paddingsTypedArray.getDimensionPixelSize(1, padding);
+        innerPaddingTop = paddingsTypedArray.getDimensionPixelSize(2, padding);
+        innerPaddingRight = paddingsTypedArray.getDimensionPixelSize(3, padding);
+        innerPaddingBottom = paddingsTypedArray.getDimensionPixelSize(4, padding);
+        paddingsTypedArray.recycle();
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+            setBackground(null);
         } else {
-          throw new RuntimeException("colorPrimary not found");
+            setBackgroundDrawable(null);
+        }
+        if (singleLineEllipsis) {
+            TransformationMethod transformationMethod = getTransformationMethod();
+            setSingleLine();
+            setTransformationMethod(transformationMethod);
         }
-      } catch (Exception e1) {
-        defaultPrimaryColor = baseColor;
-      }
-    }
-
-    primaryColor = typedArray.getColor(R.styleable.MaterialEditText_met_primaryColor, defaultPrimaryColor);
-    setFloatingLabelInternal(typedArray.getInt(R.styleable.MaterialEditText_met_floatingLabel, 0));
-    errorColor = typedArray.getColor(R.styleable.MaterialEditText_met_errorColor, Color.parseColor("#e7492E"));
-    minCharacters = typedArray.getInt(R.styleable.MaterialEditText_met_minCharacters, 0);
-    maxCharacters = typedArray.getInt(R.styleable.MaterialEditText_met_maxCharacters, 0);
-    singleLineEllipsis = typedArray.getBoolean(R.styleable.MaterialEditText_met_singleLineEllipsis, false);
-    helperText = typedArray.getString(R.styleable.MaterialEditText_met_helperText);
-    helperTextColor = typedArray.getColor(R.styleable.MaterialEditText_met_helperTextColor, -1);
-    minBottomTextLines = typedArray.getInt(R.styleable.MaterialEditText_met_minBottomTextLines, 0);
-    String fontPathForAccent = typedArray.getString(R.styleable.MaterialEditText_met_accentTypeface);
-    if (fontPathForAccent != null && !isInEditMode()) {
-      accentTypeface = getCustomTypeface(fontPathForAccent);
-      textPaint.setTypeface(accentTypeface);
-    }
-    String fontPathForView = typedArray.getString(R.styleable.MaterialEditText_met_typeface);
-    if (fontPathForView != null && !isInEditMode()) {
-      typeface = getCustomTypeface(fontPathForView);
-      setTypeface(typeface);
-    }
-    floatingLabelText = typedArray.getString(R.styleable.MaterialEditText_met_floatingLabelText);
-    if (floatingLabelText == null) {
-      floatingLabelText = getHint();
-    }
-    floatingLabelPadding = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_floatingLabelPadding, bottomSpacing);
-    floatingLabelTextSize = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_floatingLabelTextSize, getResources().getDimensionPixelSize(R.dimen.floating_label_text_size));
-    floatingLabelTextColor = typedArray.getColor(R.styleable.MaterialEditText_met_floatingLabelTextColor, -1);
-    floatingLabelAnimating = typedArray.getBoolean(R.styleable.MaterialEditText_met_floatingLabelAnimating, true);
-    bottomTextSize = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_bottomTextSize, getResources().getDimensionPixelSize(R.dimen.bottom_text_size));
-    hideUnderline = typedArray.getBoolean(R.styleable.MaterialEditText_met_hideUnderline, false);
-    underlineColor = typedArray.getColor(R.styleable.MaterialEditText_met_underlineColor, -1);
-    autoValidate = typedArray.getBoolean(R.styleable.MaterialEditText_met_autoValidate, false);
-    iconLeftBitmaps = generateIconBitmaps(typedArray.getResourceId(R.styleable.MaterialEditText_met_iconLeft, -1));
-    iconRightBitmaps = generateIconBitmaps(typedArray.getResourceId(R.styleable.MaterialEditText_met_iconRight, -1));
-    showClearButton = typedArray.getBoolean(R.styleable.MaterialEditText_met_clearButton, false);
-    clearButtonBitmaps = generateIconBitmaps(R.drawable.met_ic_clear);
-    iconPadding = typedArray.getDimensionPixelSize(R.styleable.MaterialEditText_met_iconPadding, getPixel(16));
-    floatingLabelAlwaysShown = typedArray.getBoolean(R.styleable.MaterialEditText_met_floatingLabelAlwaysShown, false);
-    helperTextAlwaysShown = typedArray.getBoolean(R.styleable.MaterialEditText_met_helperTextAlwaysShown, false);
-    validateOnFocusLost = typedArray.getBoolean(R.styleable.MaterialEditText_met_validateOnFocusLost, false);
-    checkCharactersCountAtBeginning = typedArray.getBoolean(R.styleable.MaterialEditText_met_checkCharactersCountAtBeginning, true);
-    typedArray.recycle();
-
-    int[] paddings = new int[]{
-        android.R.attr.padding, // 0
-        android.R.attr.paddingLeft, // 1
-        android.R.attr.paddingTop, // 2
-        android.R.attr.paddingRight, // 3
-        android.R.attr.paddingBottom // 4
-    };
-    TypedArray paddingsTypedArray = context.obtainStyledAttributes(attrs, paddings);
-    int padding = paddingsTypedArray.getDimensionPixelSize(0, 0);
-    innerPaddingLeft = paddingsTypedArray.getDimensionPixelSize(1, padding);
-    innerPaddingTop = paddingsTypedArray.getDimensionPixelSize(2, padding);
-    innerPaddingRight = paddingsTypedArray.getDimensionPixelSize(3, padding);
-    innerPaddingBottom = paddingsTypedArray.getDimensionPixelSize(4, padding);
-    paddingsTypedArray.recycle();
-
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-      setBackground(null);
-    } else {
-      setBackgroundDrawable(null);
-    }
-    if (singleLineEllipsis) {
-      TransformationMethod transformationMethod = getTransformationMethod();
-      setSingleLine();
-      setTransformationMethod(transformationMethod);
-    }
-    initMinBottomLines();
-    initPadding();
-    initText();
-    initFloatingLabel();
-    initTextWatcher();
-    checkCharactersCount();
-  }
-
-  private void initText() {
-    if (!TextUtils.isEmpty(getText())) {
-      CharSequence text = getText();
-      setText(null);
-      resetHintTextColor();
-      setText(text);
-      setSelection(text.length());
-      floatingLabelFraction = 1;
-      floatingLabelShown = true;
-    } else {
-      resetHintTextColor();
-    }
-    resetTextColor();
-  }
-
-  private void initTextWatcher() {
-    addTextChangedListener(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) {
-      }
-
-      @Override
-      public void afterTextChanged(Editable s) {
+        initMinBottomLines();
+        initPadding();
+        initText();
+        initFloatingLabel();
+        initTextWatcher();
         checkCharactersCount();
-        if (autoValidate) {
-          validate();
+    }
+
+    private void initText() {
+        if (!TextUtils.isEmpty(getText())) {
+            CharSequence text = getText();
+            setText(null);
+            resetHintTextColor();
+            setText(text);
+            setSelection(text.length());
+            floatingLabelFraction = 1;
+            floatingLabelShown = true;
         } else {
-          setError(null);
+            resetHintTextColor();
         }
-        postInvalidate();
-      }
-    });
-  }
-
-  private Typeface getCustomTypeface(@NonNull String fontPath) {
-    return Typeface.createFromAsset(getContext().getAssets(), fontPath);
-  }
-
-  public void setIconLeft(@DrawableRes int res) {
-    iconLeftBitmaps = generateIconBitmaps(res);
-    initPadding();
-  }
-
-  public void setIconLeft(Drawable drawable) {
-    iconLeftBitmaps = generateIconBitmaps(drawable);
-    initPadding();
-  }
-
-  public void setIconLeft(Bitmap bitmap) {
-    iconLeftBitmaps = generateIconBitmaps(bitmap);
-    initPadding();
-  }
-
-  public void setIconRight(@DrawableRes int res) {
-    iconRightBitmaps = generateIconBitmaps(res);
-    initPadding();
-  }
-
-  public void setIconRight(Drawable drawable) {
-    iconRightBitmaps = generateIconBitmaps(drawable);
-    initPadding();
-  }
-
-  public void setIconRight(Bitmap bitmap) {
-    iconRightBitmaps = generateIconBitmaps(bitmap);
-    initPadding();
-  }
-
-  public boolean isShowClearButton() {
-    return showClearButton;
-  }
-
-  public void setShowClearButton(boolean show) {
-    showClearButton = show;
-    correctPaddings();
-  }
-
-  private Bitmap[] generateIconBitmaps(@DrawableRes int origin) {
-    if (origin == -1) {
-      return null;
-    }
-    BitmapFactory.Options options = new BitmapFactory.Options();
-    options.inJustDecodeBounds = true;
-    BitmapFactory.decodeResource(getResources(), origin, options);
-    int size = Math.max(options.outWidth, options.outHeight);
-    options.inSampleSize = size > iconSize ? size / iconSize : 1;
-    options.inJustDecodeBounds = false;
-    return generateIconBitmaps(BitmapFactory.decodeResource(getResources(), origin, options));
-  }
-
-  private Bitmap[] generateIconBitmaps(Drawable drawable) {
-    if (drawable == null)
-      return null;
-    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
-    Canvas canvas = new Canvas(bitmap);
-    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
-    drawable.draw(canvas);
-    return generateIconBitmaps(Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, false));
-  }
-
-  private Bitmap[] generateIconBitmaps(Bitmap origin) {
-    if (origin == null) {
-      return null;
-    }
-    Bitmap[] iconBitmaps = new Bitmap[4];
-    origin = scaleIcon(origin);
-    iconBitmaps[0] = origin.copy(Bitmap.Config.ARGB_8888, true);
-    Canvas canvas = new Canvas(iconBitmaps[0]);
-    canvas.drawColor(baseColor & 0x00ffffff | (Colors.isLight(baseColor) ? 0xff000000 : 0x8a000000), PorterDuff.Mode.SRC_IN);
-    iconBitmaps[1] = origin.copy(Bitmap.Config.ARGB_8888, true);
-    canvas = new Canvas(iconBitmaps[1]);
-    canvas.drawColor(primaryColor, PorterDuff.Mode.SRC_IN);
-    iconBitmaps[2] = origin.copy(Bitmap.Config.ARGB_8888, true);
-    canvas = new Canvas(iconBitmaps[2]);
-    canvas.drawColor(baseColor & 0x00ffffff | (Colors.isLight(baseColor) ? 0x4c000000 : 0x42000000), PorterDuff.Mode.SRC_IN);
-    iconBitmaps[3] = origin.copy(Bitmap.Config.ARGB_8888, true);
-    canvas = new Canvas(iconBitmaps[3]);
-    canvas.drawColor(errorColor, PorterDuff.Mode.SRC_IN);
-    return iconBitmaps;
-  }
-
-  private Bitmap scaleIcon(Bitmap origin) {
-    int width = origin.getWidth();
-    int height = origin.getHeight();
-    int size = Math.max(width, height);
-    if (size == iconSize) {
-      return origin;
-    } else if (size > iconSize) {
-      int scaledWidth;
-      int scaledHeight;
-      if (width > iconSize) {
-        scaledWidth = iconSize;
-        scaledHeight = (int) (iconSize * ((float) height / width));
-      } else {
-        scaledHeight = iconSize;
-        scaledWidth = (int) (iconSize * ((float) width / height));
-      }
-      return Bitmap.createScaledBitmap(origin, scaledWidth, scaledHeight, false);
-    } else {
-      return origin;
-    }
-  }
-
-  public float getFloatingLabelFraction() {
-    return floatingLabelFraction;
-  }
-
-  public void setFloatingLabelFraction(float floatingLabelFraction) {
-    this.floatingLabelFraction = floatingLabelFraction;
-    invalidate();
-  }
-
-  public float getFocusFraction() {
-    return focusFraction;
-  }
-
-  public void setFocusFraction(float focusFraction) {
-    this.focusFraction = focusFraction;
-    invalidate();
-  }
-
-  public float getCurrentBottomLines() {
-    return currentBottomLines;
-  }
-
-  public void setCurrentBottomLines(float currentBottomLines) {
-    this.currentBottomLines = currentBottomLines;
-    initPadding();
-  }
-
-  public boolean isFloatingLabelAlwaysShown() {
-    return floatingLabelAlwaysShown;
-  }
-
-  public void setFloatingLabelAlwaysShown(boolean floatingLabelAlwaysShown) {
-    this.floatingLabelAlwaysShown = floatingLabelAlwaysShown;
-    invalidate();
-  }
-
-  public boolean isHelperTextAlwaysShown() {
-    return helperTextAlwaysShown;
-  }
-
-  public void setHelperTextAlwaysShown(boolean helperTextAlwaysShown) {
-    this.helperTextAlwaysShown = helperTextAlwaysShown;
-    invalidate();
-  }
-
-  @Nullable
-  public Typeface getAccentTypeface() {
-    return accentTypeface;
-  }
-
-  /**
-   * Set typeface used for the accent texts (floating label, error/helper text, character counter, etc.)
-   */
-  public void setAccentTypeface(Typeface accentTypeface) {
-    this.accentTypeface = accentTypeface;
-    this.textPaint.setTypeface(accentTypeface);
-    postInvalidate();
-  }
-
-  public boolean isHideUnderline() {
-    return hideUnderline;
-  }
-
-  /**
-   * Set whether or not to hide the underline (shown by default).
-   * <p/>
-   * The positions of text below will be adjusted accordingly (error/helper text, character counter, ellipses, etc.)
-   * <p/>
-   * NOTE: You probably don't want to hide this if you have any subtext features of this enabled, as it can look weird to not have a dividing line between them.
-   */
-  public void setHideUnderline(boolean hideUnderline) {
-    this.hideUnderline = hideUnderline;
-    initPadding();
-    postInvalidate();
-  }
-
-  /**
-   * get the color of the underline for normal state
-   */
-  public int getUnderlineColor() {
-    return underlineColor;
-  }
-
-  /**
-   * Set the color of the underline for normal state
-   * @param color
-   */
-  public void setUnderlineColor(int color) {
-    this.underlineColor = color;
-    postInvalidate();
-  }
-
-  public CharSequence getFloatingLabelText() {
-    return floatingLabelText;
-  }
-
-  /**
-   * Set the floating label text.
-   * <p/>
-   * Pass null to force fallback to use hint's value.
-   *
-   * @param floatingLabelText
-   */
-  public void setFloatingLabelText(@Nullable CharSequence floatingLabelText) {
-    this.floatingLabelText = floatingLabelText == null ? getHint() : floatingLabelText;
-    postInvalidate();
-  }
-
-  public int getFloatingLabelTextSize() {
-    return floatingLabelTextSize;
-  }
-
-  public void setFloatingLabelTextSize(int size) {
-    floatingLabelTextSize = size;
-    initPadding();
-  }
-
-  public int getFloatingLabelTextColor() {
-    return floatingLabelTextColor;
-  }
-
-  public void setFloatingLabelTextColor(int color) {
-    this.floatingLabelTextColor = color;
-    postInvalidate();
-  }
-
-  public int getBottomTextSize() {
-    return bottomTextSize;
-  }
-
-  public void setBottomTextSize(int size) {
-    bottomTextSize = size;
-    initPadding();
-  }
-
-  private int getPixel(int dp) {
-    return Density.dp2px(getContext(), dp);
-  }
-
-  private void initPadding() {
-    extraPaddingTop = floatingLabelEnabled ? floatingLabelTextSize + floatingLabelPadding : floatingLabelPadding;
-    textPaint.setTextSize(bottomTextSize);
-    Paint.FontMetrics textMetrics = textPaint.getFontMetrics();
-    extraPaddingBottom = (int) ((textMetrics.descent - textMetrics.ascent) * currentBottomLines) + (hideUnderline ? bottomSpacing : bottomSpacing * 2);
-    extraPaddingLeft = iconLeftBitmaps == null ? 0 : (iconOuterWidth + iconPadding);
-    extraPaddingRight = iconRightBitmaps == null ? 0 : (iconOuterWidth + iconPadding);
-    correctPaddings();
-  }
-
-  /**
-   * calculate {@link #minBottomLines}
-   */
-  private void initMinBottomLines() {
-    boolean extendBottom = minCharacters > 0 || maxCharacters > 0 || singleLineEllipsis || tempErrorText != null || helperText != null;
-    currentBottomLines = minBottomLines = minBottomTextLines > 0 ? minBottomTextLines : extendBottom ? 1 : 0;
-  }
-
-  /**
-   * use {@link #setPaddings(int, int, int, int)} instead, or the paddingTop and the paddingBottom may be set incorrectly.
-   */
-  @Deprecated
-  @Override
-  public final void setPadding(int left, int top, int right, int bottom) {
-    super.setPadding(left, top, right, bottom);
-  }
-
-  /**
-   * Use this method instead of {@link #setPadding(int, int, int, int)} to automatically set the paddingTop and the paddingBottom correctly.
-   */
-  public void setPaddings(int left, int top, int right, int bottom) {
-    innerPaddingTop = top;
-    innerPaddingBottom = bottom;
-    innerPaddingLeft = left;
-    innerPaddingRight = right;
-    correctPaddings();
-  }
-
-  /**
-   * Set paddings to the correct values
-   */
-  private void correctPaddings() {
-    int buttonsWidthLeft = 0, buttonsWidthRight = 0;
-    int buttonsWidth = iconOuterWidth * getButtonsCount();
-    if (isRTL()) {
-      buttonsWidthLeft = buttonsWidth;
-    } else {
-      buttonsWidthRight = buttonsWidth;
-    }
-    super.setPadding(innerPaddingLeft + extraPaddingLeft + buttonsWidthLeft, innerPaddingTop + extraPaddingTop, innerPaddingRight + extraPaddingRight + buttonsWidthRight, innerPaddingBottom + extraPaddingBottom);
-  }
-
-  private int getButtonsCount() {
-    return isShowClearButton() ? 1 : 0;
-  }
-
-  @Override
-  protected void onAttachedToWindow() {
-    super.onAttachedToWindow();
-    if (!firstShown) {
-      firstShown = true;
-    }
-  }
-
-  @Override
-  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-    super.onLayout(changed, left, top, right, bottom);
-    if (changed) {
-      adjustBottomLines();
-    }
-  }
-
-  /**
-   * @return True, if adjustments were made that require the view to be invalidated.
-   */
-  private boolean adjustBottomLines() {
-    // Bail out if we have a zero width; lines will be adjusted during next layout.
-    if (getWidth() == 0) {
-      return false;
-    }
-    int destBottomLines;
-    textPaint.setTextSize(bottomTextSize);
-    if (tempErrorText != null || helperText != null) {
-      Layout.Alignment alignment = (getGravity() & Gravity.RIGHT) == Gravity.RIGHT || isRTL() ?
-          Layout.Alignment.ALIGN_OPPOSITE : (getGravity() & Gravity.LEFT) == Gravity.LEFT ?
-          Layout.Alignment.ALIGN_NORMAL : Layout.Alignment.ALIGN_CENTER;
-      textLayout = new StaticLayout(tempErrorText != null ? tempErrorText : helperText, textPaint, getWidth() - getBottomTextLeftOffset() - getBottomTextRightOffset() - getPaddingLeft() - getPaddingRight(), alignment, 1.0f, 0.0f, true);
-      destBottomLines = Math.max(textLayout.getLineCount(), minBottomTextLines);
-    } else {
-      destBottomLines = minBottomLines;
-    }
-    if (bottomLines != destBottomLines) {
-      getBottomLinesAnimator(destBottomLines).start();
-    }
-    bottomLines = destBottomLines;
-    return true;
-  }
-
-  /**
-   * get inner top padding, not the real paddingTop
-   */
-  public int getInnerPaddingTop() {
-    return innerPaddingTop;
-  }
-
-  /**
-   * get inner bottom padding, not the real paddingBottom
-   */
-  public int getInnerPaddingBottom() {
-    return innerPaddingBottom;
-  }
-
-  /**
-   * get inner left padding, not the real paddingLeft
-   */
-  public int getInnerPaddingLeft() {
-    return innerPaddingLeft;
-  }
-
-  /**
-   * get inner right padding, not the real paddingRight
-   */
-  public int getInnerPaddingRight() {
-    return innerPaddingRight;
-  }
-
-  private void initFloatingLabel() {
-    // observe the text changing
-    addTextChangedListener(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) {
-      }
-
-      @Override
-      public void afterTextChanged(Editable s) {
-        if (floatingLabelEnabled) {
-          if (s.length() == 0) {
-            if (floatingLabelShown) {
-              floatingLabelShown = false;
-              getLabelAnimator().reverse();
+        resetTextColor();
+    }
+
+    private void initTextWatcher() {
+        addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
             }
-          } else if (!floatingLabelShown) {
-            floatingLabelShown = true;
-            getLabelAnimator().start();
-          }
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+            }
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                checkCharactersCount();
+                if (autoValidate) {
+                    validate();
+                } else {
+                    setError(null);
+                }
+                postInvalidate();
+            }
+        });
+    }
+
+    private Typeface getCustomTypeface(@NonNull String fontPath) {
+        return Typeface.createFromAsset(getContext().getAssets(), fontPath);
+    }
+
+    public void setIconLeft(@DrawableRes int res) {
+        iconLeftBitmaps = generateIconBitmaps(res);
+        initPadding();
+    }
+
+    public void setIconLeft(Drawable drawable) {
+        iconLeftBitmaps = generateIconBitmaps(drawable);
+        initPadding();
+    }
+
+    public void setIconLeft(Bitmap bitmap) {
+        iconLeftBitmaps = generateIconBitmaps(bitmap);
+        initPadding();
+    }
+
+    public void setIconRight(@DrawableRes int res) {
+        iconRightBitmaps = generateIconBitmaps(res);
+        initPadding();
+    }
+
+    public void setIconRight(Drawable drawable) {
+        iconRightBitmaps = generateIconBitmaps(drawable);
+        initPadding();
+    }
+
+    public void setIconRight(Bitmap bitmap) {
+        iconRightBitmaps = generateIconBitmaps(bitmap);
+        initPadding();
+    }
+
+    public boolean isShowClearButton() {
+        return showClearButton;
+    }
+
+    public void setShowClearButton(boolean show) {
+        showClearButton = show;
+        correctPaddings();
+    }
+
+    private Bitmap[] generateIconBitmaps(@DrawableRes int origin) {
+        if (origin == -1) {
+            return null;
+        }
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeResource(getResources(), origin, options);
+        int size = Math.max(options.outWidth, options.outHeight);
+        options.inSampleSize = size > iconSize ? size / iconSize : 1;
+        options.inJustDecodeBounds = false;
+        return generateIconBitmaps(BitmapFactory.decodeResource(getResources(), origin, options));
+    }
+
+    private Bitmap[] generateIconBitmaps(Drawable drawable) {
+        if (drawable == null)
+            return null;
+        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        drawable.draw(canvas);
+        return generateIconBitmaps(Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, false));
+    }
+
+    private Bitmap[] generateIconBitmaps(Bitmap origin) {
+        if (origin == null) {
+            return null;
+        }
+        Bitmap[] iconBitmaps = new Bitmap[4];
+        origin = scaleIcon(origin);
+        iconBitmaps[0] = origin.copy(Bitmap.Config.ARGB_8888, true);
+        Canvas canvas = new Canvas(iconBitmaps[0]);
+        canvas.drawColor(baseColor & 0x00ffffff | (Colors.isLight(baseColor) ? 0xff000000 : 0x8a000000), PorterDuff.Mode.SRC_IN);
+        iconBitmaps[1] = origin.copy(Bitmap.Config.ARGB_8888, true);
+        canvas = new Canvas(iconBitmaps[1]);
+        canvas.drawColor(primaryColor, PorterDuff.Mode.SRC_IN);
+        iconBitmaps[2] = origin.copy(Bitmap.Config.ARGB_8888, true);
+        canvas = new Canvas(iconBitmaps[2]);
+        canvas.drawColor(baseColor & 0x00ffffff | (Colors.isLight(baseColor) ? 0x4c000000 : 0x42000000), PorterDuff.Mode.SRC_IN);
+        iconBitmaps[3] = origin.copy(Bitmap.Config.ARGB_8888, true);
+        canvas = new Canvas(iconBitmaps[3]);
+        canvas.drawColor(errorColor, PorterDuff.Mode.SRC_IN);
+        return iconBitmaps;
+    }
+
+    private Bitmap scaleIcon(Bitmap origin) {
+        int width = origin.getWidth();
+        int height = origin.getHeight();
+        int size = Math.max(width, height);
+        if (size == iconSize) {
+            return origin;
+        } else if (size > iconSize) {
+            int scaledWidth;
+            int scaledHeight;
+            if (width > iconSize) {
+                scaledWidth = iconSize;
+                scaledHeight = (int) (iconSize * ((float) height / width));
+            } else {
+                scaledHeight = iconSize;
+                scaledWidth = (int) (iconSize * ((float) width / height));
+            }
+            return Bitmap.createScaledBitmap(origin, scaledWidth, scaledHeight, false);
+        } else {
+            return origin;
         }
-      }
-    });
-    // observe the focus state to animate the floating label's text color appropriately
-    innerFocusChangeListener = new OnFocusChangeListener() {
-      @Override
-      public void onFocusChange(View v, boolean hasFocus) {
-        if (floatingLabelEnabled && highlightFloatingLabel) {
-          if (hasFocus) {
-            getLabelFocusAnimator().start();
-          } else {
-            getLabelFocusAnimator().reverse();
-          }
+    }
+
+    public float getFloatingLabelFraction() {
+        return floatingLabelFraction;
+    }
+
+    public void setFloatingLabelFraction(float floatingLabelFraction) {
+        this.floatingLabelFraction = floatingLabelFraction;
+        invalidate();
+    }
+
+    public float getFocusFraction() {
+        return focusFraction;
+    }
+
+    public void setFocusFraction(float focusFraction) {
+        this.focusFraction = focusFraction;
+        invalidate();
+    }
+
+    public float getCurrentBottomLines() {
+        return currentBottomLines;
+    }
+
+    public void setCurrentBottomLines(float currentBottomLines) {
+        this.currentBottomLines = currentBottomLines;
+        initPadding();
+    }
+
+    public boolean isFloatingLabelAlwaysShown() {
+        return floatingLabelAlwaysShown;
+    }
+
+    public void setFloatingLabelAlwaysShown(boolean floatingLabelAlwaysShown) {
+        this.floatingLabelAlwaysShown = floatingLabelAlwaysShown;
+        invalidate();
+    }
+
+    public boolean isHelperTextAlwaysShown() {
+        return helperTextAlwaysShown;
+    }
+
+    public void setHelperTextAlwaysShown(boolean helperTextAlwaysShown) {
+        this.helperTextAlwaysShown = helperTextAlwaysShown;
+        invalidate();
+    }
+
+    @Nullable
+    public Typeface getAccentTypeface() {
+        return accentTypeface;
+    }
+
+    /**
+     * Set typeface used for the accent texts (floating label, error/helper text, character counter, etc.)
+     */
+    public void setAccentTypeface(Typeface accentTypeface) {
+        this.accentTypeface = accentTypeface;
+        this.textPaint.setTypeface(accentTypeface);
+        postInvalidate();
+    }
+
+    public boolean isHideUnderline() {
+        return hideUnderline;
+    }
+
+    /**
+     * Set whether or not to hide the underline (shown by default).
+     * <p/>
+     * The positions of text below will be adjusted accordingly (error/helper text, character counter, ellipses, etc.)
+     * <p/>
+     * NOTE: You probably don't want to hide this if you have any subtext features of this enabled, as it can look weird to not have a dividing line between them.
+     */
+    public void setHideUnderline(boolean hideUnderline) {
+        this.hideUnderline = hideUnderline;
+        initPadding();
+        postInvalidate();
+    }
+
+    /**
+     * get the color of the underline for normal state
+     */
+    public int getUnderlineColor() {
+        return underlineColor;
+    }
+
+    /**
+     * Set the color of the underline for normal state
+     *
+     * @param color
+     */
+    public void setUnderlineColor(int color) {
+        this.underlineColor = color;
+        postInvalidate();
+    }
+
+    public CharSequence getFloatingLabelText() {
+        return floatingLabelText;
+    }
+
+    /**
+     * Set the floating label text.
+     * <p/>
+     * Pass null to force fallback to use hint's value.
+     *
+     * @param floatingLabelText
+     */
+    public void setFloatingLabelText(@Nullable CharSequence floatingLabelText) {
+        this.floatingLabelText = floatingLabelText == null ? getHint() : floatingLabelText;
+        postInvalidate();
+    }
+
+    public int getFloatingLabelTextSize() {
+        return floatingLabelTextSize;
+    }
+
+    public void setFloatingLabelTextSize(int size) {
+        floatingLabelTextSize = size;
+        initPadding();
+    }
+
+    public int getFloatingLabelTextColor() {
+        return floatingLabelTextColor;
+    }
+
+    public void setFloatingLabelTextColor(int color) {
+        this.floatingLabelTextColor = color;
+        postInvalidate();
+    }
+
+    public int getBottomTextSize() {
+        return bottomTextSize;
+    }
+
+    public void setBottomTextSize(int size) {
+        bottomTextSize = size;
+        initPadding();
+    }
+
+    private int getPixel(int dp) {
+        return Density.dp2px(getContext(), dp);
+    }
+
+    private void initPadding() {
+        extraPaddingTop = floatingLabelEnabled ? floatingLabelTextSize + floatingLabelPadding : floatingLabelPadding;
+        textPaint.setTextSize(bottomTextSize);
+        Paint.FontMetrics textMetrics = textPaint.getFontMetrics();
+        extraPaddingBottom = (int) ((textMetrics.descent - textMetrics.ascent) * currentBottomLines) + (hideUnderline ? bottomSpacing : bottomSpacing * 2);
+        extraPaddingLeft = iconLeftBitmaps == null ? 0 : (iconOuterWidth + iconPadding);
+        extraPaddingRight = iconRightBitmaps == null ? 0 : (iconOuterWidth + iconPadding);
+        correctPaddings();
+    }
+
+    /**
+     * calculate {@link #minBottomLines}
+     */
+    private void initMinBottomLines() {
+        boolean extendBottom = minCharacters > 0 || maxCharacters > 0 || singleLineEllipsis || tempErrorText != null || helperText != null;
+        currentBottomLines = minBottomLines = minBottomTextLines > 0 ? minBottomTextLines : extendBottom ? 1 : 0;
+    }
+
+    /**
+     * use {@link #setPaddings(int, int, int, int)} instead, or the paddingTop and the paddingBottom may be set incorrectly.
+     */
+    @Deprecated
+    @Override
+    public final void setPadding(int left, int top, int right, int bottom) {
+        super.setPadding(left, top, right, bottom);
+    }
+
+    /**
+     * Use this method instead of {@link #setPadding(int, int, int, int)} to automatically set the paddingTop and the paddingBottom correctly.
+     */
+    public void setPaddings(int left, int top, int right, int bottom) {
+        innerPaddingTop = top;
+        innerPaddingBottom = bottom;
+        innerPaddingLeft = left;
+        innerPaddingRight = right;
+        correctPaddings();
+    }
+
+    /**
+     * Set paddings to the correct values
+     */
+    private void correctPaddings() {
+        int buttonsWidthLeft = 0, buttonsWidthRight = 0;
+        int buttonsWidth = iconOuterWidth * getButtonsCount();
+        if (isRTL()) {
+            buttonsWidthLeft = buttonsWidth;
+        } else {
+            buttonsWidthRight = buttonsWidth;
         }
-        if (validateOnFocusLost && !hasFocus) {
-          validate();
+        super.setPadding(innerPaddingLeft + extraPaddingLeft + buttonsWidthLeft, innerPaddingTop + extraPaddingTop, innerPaddingRight + extraPaddingRight + buttonsWidthRight, innerPaddingBottom + extraPaddingBottom);
+    }
+
+    private int getButtonsCount() {
+        return isShowClearButton() ? 1 : 0;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (!firstShown) {
+            firstShown = true;
         }
-        if (outerFocusChangeListener != null) {
-          outerFocusChangeListener.onFocusChange(v, hasFocus);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (changed) {
+            adjustBottomLines();
         }
-      }
-    };
-    super.setOnFocusChangeListener(innerFocusChangeListener);
-  }
-
-  public boolean isValidateOnFocusLost() {
-    return validateOnFocusLost;
-  }
-
-  public void setValidateOnFocusLost(boolean validate) {
-    this.validateOnFocusLost = validate;
-  }
-
-  public void setBaseColor(int color) {
-    if (baseColor != color) {
-      baseColor = color;
-    }
-
-    initText();
-
-    postInvalidate();
-  }
-
-  public void setPrimaryColor(int color) {
-    primaryColor = color;
-    postInvalidate();
-  }
-
-  /**
-   * Same function as {@link #setTextColor(int)}. (Directly overriding the built-in one could cause some error, so use this method instead.)
-   */
-  public void setMetTextColor(int color) {
-    textColorStateList = ColorStateList.valueOf(color);
-    resetTextColor();
-  }
-
-  /**
-   * Same function as {@link #setTextColor(ColorStateList)}. (Directly overriding the built-in one could cause some error, so use this method instead.)
-   */
-  public void setMetTextColor(ColorStateList colors) {
-    textColorStateList = colors;
-    resetTextColor();
-  }
-
-  private void resetTextColor() {
-    if (textColorStateList == null) {
-      textColorStateList = new ColorStateList(new int[][]{new int[]{android.R.attr.state_enabled}, EMPTY_STATE_SET}, new int[]{baseColor & 0x00ffffff | 0xdf000000, baseColor & 0x00ffffff | 0x44000000});
-      setTextColor(textColorStateList);
-    } else {
-      setTextColor(textColorStateList);
-    }
-  }
-
-  /**
-   * Same function as {@link #setHintTextColor(int)}. (The built-in one is a final method that can't be overridden, so use this method instead.)
-   */
-  public void setMetHintTextColor(int color) {
-    textColorHintStateList = ColorStateList.valueOf(color);
-    resetHintTextColor();
-  }
-
-  /**
-   * Same function as {@link #setHintTextColor(ColorStateList)}. (The built-in one is a final method that can't be overridden, so use this method instead.)
-   */
-  public void setMetHintTextColor(ColorStateList colors) {
-    textColorHintStateList = colors;
-    resetHintTextColor();
-  }
-
-  private void resetHintTextColor() {
-    if (textColorHintStateList == null) {
-      setHintTextColor(baseColor & 0x00ffffff | 0x44000000);
-    } else {
-      setHintTextColor(textColorHintStateList);
-    }
-  }
-
-  private void setFloatingLabelInternal(int mode) {
-    switch (mode) {
-      case FLOATING_LABEL_NORMAL:
-        floatingLabelEnabled = true;
-        highlightFloatingLabel = false;
-        break;
-      case FLOATING_LABEL_HIGHLIGHT:
-        floatingLabelEnabled = true;
-        highlightFloatingLabel = true;
-        break;
-      default:
-        floatingLabelEnabled = false;
-        highlightFloatingLabel = false;
-        break;
-    }
-  }
-
-  public void setFloatingLabel(@FloatingLabelType int mode) {
-    setFloatingLabelInternal(mode);
-    initPadding();
-  }
-
-  public int getFloatingLabelPadding() {
-    return floatingLabelPadding;
-  }
-
-  public void setFloatingLabelPadding(int padding) {
-    floatingLabelPadding = padding;
-    postInvalidate();
-  }
-
-  public boolean isFloatingLabelAnimating() {
-    return floatingLabelAnimating;
-  }
-
-  public void setFloatingLabelAnimating(boolean animating) {
-    floatingLabelAnimating = animating;
-  }
-
-  public void setSingleLineEllipsis() {
-    setSingleLineEllipsis(true);
-  }
-
-  public void setSingleLineEllipsis(boolean enabled) {
-    singleLineEllipsis = enabled;
-    initMinBottomLines();
-    initPadding();
-    postInvalidate();
-  }
-
-  public int getMaxCharacters() {
-    return maxCharacters;
-  }
-
-  public void setMaxCharacters(int max) {
-    maxCharacters = max;
-    initMinBottomLines();
-    initPadding();
-    postInvalidate();
-  }
-
-  public int getMinCharacters() {
-    return minCharacters;
-  }
-
-  public void setMinCharacters(int min) {
-    minCharacters = min;
-    initMinBottomLines();
-    initPadding();
-    postInvalidate();
-  }
-
-  public int getMinBottomTextLines() {
-    return minBottomTextLines;
-  }
-
-  public void setMinBottomTextLines(int lines) {
-    minBottomTextLines = lines;
-    initMinBottomLines();
-    initPadding();
-    postInvalidate();
-  }
-
-  public boolean isAutoValidate() {
-    return autoValidate;
-  }
-
-  public void setAutoValidate(boolean autoValidate) {
-    this.autoValidate = autoValidate;
-    if (autoValidate) {
-      validate();
-    }
-  }
-
-  public int getErrorColor() {
-    return errorColor;
-  }
-
-  public void setErrorColor(int color) {
-    errorColor = color;
-    postInvalidate();
-  }
-
-  public void setHelperText(CharSequence helperText) {
-    this.helperText = helperText == null ? null : helperText.toString();
-    if (adjustBottomLines()) {
-      postInvalidate();
-    }
-  }
-
-  public String getHelperText() {
-    return helperText;
-  }
-
-  public int getHelperTextColor() {
-    return helperTextColor;
-  }
-
-  public void setHelperTextColor(int color) {
-    helperTextColor = color;
-    postInvalidate();
-  }
-
-  @Override
-  public void setError(CharSequence errorText) {
-    tempErrorText = errorText == null ? null : errorText.toString();
-    if (adjustBottomLines()) {
-      postInvalidate();
-    }
-  }
-
-  @Override
-  public CharSequence getError() {
-    return tempErrorText;
-  }
-
-  /**
-   * only used to draw the bottom line
-   */
-  private boolean isInternalValid() {
-    return tempErrorText == null && isCharactersCountValid();
-  }
-
-  /**
-   * if the main text matches the regex
-   *
-   * @deprecated use the new validator interface to add your own custom validator
-   */
-  @Deprecated
-  public boolean isValid(String regex) {
-    if (regex == null) {
-      return false;
-    }
-    Pattern pattern = Pattern.compile(regex);
-    Matcher matcher = pattern.matcher(getText());
-    return matcher.matches();
-  }
-
-  /**
-   * check if the main text matches the regex, and set the error text if not.
-   *
-   * @return true if it matches the regex, false if not.
-   * @deprecated use the new validator interface to add your own custom validator
-   */
-  @Deprecated
-  public boolean validate(String regex, CharSequence errorText) {
-    boolean isValid = isValid(regex);
-    if (!isValid) {
-      setError(errorText);
-    }
-    postInvalidate();
-    return isValid;
-  }
-
-  /**
-   * Run validation on a single validator instance
-   *
-   * @param validator Validator to check
-   * @return True if valid, false if not
-   */
-  public boolean validateWith(@NonNull METValidator validator) {
-    CharSequence text = getText();
-    boolean isValid = validator.isValid(text, text.length() == 0);
-    if (!isValid) {
-      setError(validator.getErrorMessage());
-    }
-    postInvalidate();
-    return isValid;
-  }
-
-  /**
-   * Check all validators, sets the error text if not
-   * <p/>
-   * NOTE: this stops at the first validator to report invalid.
-   *
-   * @return True if all validators pass, false if not
-   */
-  public boolean validate() {
-    if (validators == null || validators.isEmpty()) {
-      return true;
-    }
-
-    CharSequence text = getText();
-    boolean isEmpty = text.length() == 0;
-
-    boolean isValid = true;
-    for (METValidator validator : validators) {
-      //noinspection ConstantConditions
-      isValid = isValid && validator.isValid(text, isEmpty);
-      if (!isValid) {
-        setError(validator.getErrorMessage());
-        break;
-      }
-    }
-    if (isValid) {
-      setError(null);
-    }
-
-    postInvalidate();
-    return isValid;
-  }
-
-  public boolean hasValidators() {
-    return this.validators != null && !this.validators.isEmpty();
-  }
-
-  /**
-   * Adds a new validator to the View's list of validators
-   * <p/>
-   * This will be checked with the others in {@link #validate()}
-   *
-   * @param validator Validator to add
-   * @return This instance, for easy chaining
-   */
-  public MaterialEditText addValidator(METValidator validator) {
-    if (validators == null) {
-      this.validators = new ArrayList<>();
-    }
-    this.validators.add(validator);
-    return this;
-  }
-
-  public void clearValidators() {
-    if (this.validators != null) {
-      this.validators.clear();
-    }
-  }
-
-  @Nullable
-  public List<METValidator> getValidators() {
-    return this.validators;
-  }
-
-  public void setLengthChecker(METLengthChecker lengthChecker) {
-    this.lengthChecker = lengthChecker;
-  }
-
-  @Override
-  public void setOnFocusChangeListener(OnFocusChangeListener listener) {
-    if (innerFocusChangeListener == null) {
-      super.setOnFocusChangeListener(listener);
-    } else {
-      outerFocusChangeListener = listener;
-    }
-  }
-
-  private ObjectAnimator getLabelAnimator() {
-    if (labelAnimator == null) {
-      labelAnimator = ObjectAnimator.ofFloat(this, "floatingLabelFraction", 0f, 1f);
-    }
-    labelAnimator.setDuration(floatingLabelAnimating ? 300 : 0);
-    return labelAnimator;
-  }
-
-  private ObjectAnimator getLabelFocusAnimator() {
-    if (labelFocusAnimator == null) {
-      labelFocusAnimator = ObjectAnimator.ofFloat(this, "focusFraction", 0f, 1f);
-    }
-    return labelFocusAnimator;
-  }
-
-  private ObjectAnimator getBottomLinesAnimator(float destBottomLines) {
-    if (bottomLinesAnimator == null) {
-      bottomLinesAnimator = ObjectAnimator.ofFloat(this, "currentBottomLines", destBottomLines);
-    } else {
-      bottomLinesAnimator.cancel();
-      bottomLinesAnimator.setFloatValues(destBottomLines);
-    }
-    return bottomLinesAnimator;
-  }
-
-  @Override
-  protected void onDraw(@NonNull Canvas canvas) {
-
-    int startX = getScrollX() + (iconLeftBitmaps == null ? 0 : (iconOuterWidth + iconPadding)) + getPaddingLeft();
-    int endX = getScrollX() + (iconRightBitmaps == null ? getWidth() : getWidth() - iconOuterWidth - iconPadding) - getPaddingRight();
-    int lineStartY = getScrollY() + getHeight() - getPaddingBottom();
-
-    // draw the icon(s)
-    paint.setAlpha(255);
-    if (iconLeftBitmaps != null) {
-      Bitmap icon = iconLeftBitmaps[!isInternalValid() ? 3 : !isEnabled() ? 2 : hasFocus() ? 1 : 0];
-      int iconLeft = startX - iconPadding - iconOuterWidth + (iconOuterWidth - icon.getWidth()) / 2;
-      int iconTop = lineStartY + bottomSpacing - iconOuterHeight + (iconOuterHeight - icon.getHeight()) / 2;
-      canvas.drawBitmap(icon, iconLeft, iconTop, paint);
-    }
-    if (iconRightBitmaps != null) {
-      Bitmap icon = iconRightBitmaps[!isInternalValid() ? 3 : !isEnabled() ? 2 : hasFocus() ? 1 : 0];
-      int iconRight = endX + iconPadding + (iconOuterWidth - icon.getWidth()) / 2;
-      int iconTop = lineStartY + bottomSpacing - iconOuterHeight + (iconOuterHeight - icon.getHeight()) / 2;
-      canvas.drawBitmap(icon, iconRight, iconTop, paint);
-    }
-
-    // draw the clear button
-    if (hasFocus() && showClearButton && !TextUtils.isEmpty(getText()) && isEnabled()) {
-      paint.setAlpha(255);
-      int buttonLeft;
-      if (isRTL()) {
-        buttonLeft = startX;
-      } else {
-        buttonLeft = endX - iconOuterWidth;
-      }
-      Bitmap clearButtonBitmap = clearButtonBitmaps[0];
-      buttonLeft += (iconOuterWidth - clearButtonBitmap.getWidth()) / 2;
-      int iconTop = lineStartY + bottomSpacing - iconOuterHeight + (iconOuterHeight - clearButtonBitmap.getHeight()) / 2;
-      canvas.drawBitmap(clearButtonBitmap, buttonLeft, iconTop, paint);
-    }
-
-    // draw the underline
-    if (!hideUnderline) {
-      lineStartY += bottomSpacing;
-      if (!isInternalValid()) { // not valid
-        paint.setColor(errorColor);
-        canvas.drawRect(startX, lineStartY, endX, lineStartY + getPixel(2), paint);
-      } else if (!isEnabled()) { // disabled
-        paint.setColor(underlineColor != -1 ? underlineColor : baseColor & 0x00ffffff | 0x44000000);
-        float interval = getPixel(1);
-        for (float xOffset = 0; xOffset < getWidth(); xOffset += interval * 3) {
-          canvas.drawRect(startX + xOffset, lineStartY, startX + xOffset + interval, lineStartY + getPixel(1), paint);
+    }
+
+    /**
+     * @return True, if adjustments were made that require the view to be invalidated.
+     */
+    private boolean adjustBottomLines() {
+        // Bail out if we have a zero width; lines will be adjusted during next layout.
+        if (getWidth() == 0) {
+            return false;
         }
-      } else if (hasFocus()) { // focused
-        paint.setColor(primaryColor);
-        canvas.drawRect(startX, lineStartY, endX, lineStartY + getPixel(2), paint);
-      } else { // normal
-        paint.setColor(underlineColor != -1 ? underlineColor : baseColor & 0x00ffffff | 0x1E000000);
-        canvas.drawRect(startX, lineStartY, endX, lineStartY + getPixel(1), paint);
-      }
-    }
-
-    textPaint.setTextSize(bottomTextSize);
-    Paint.FontMetrics textMetrics = textPaint.getFontMetrics();
-    float relativeHeight = -textMetrics.ascent - textMetrics.descent;
-    float bottomTextPadding = bottomTextSize + textMetrics.ascent + textMetrics.descent;
-
-    // draw the characters counter
-    if ((hasFocus() && hasCharactersCounter()) || !isCharactersCountValid()) {
-      textPaint.setColor(isCharactersCountValid() ? (baseColor & 0x00ffffff | 0x44000000) : errorColor);
-      String charactersCounterText = getCharactersCounterText();
-      canvas.drawText(charactersCounterText, isRTL() ? startX : endX - textPaint.measureText(charactersCounterText), lineStartY + bottomSpacing + relativeHeight, textPaint);
-    }
-
-    // draw the bottom text
-    if (textLayout != null) {
-      if (tempErrorText != null || ((helperTextAlwaysShown || hasFocus()) && !TextUtils.isEmpty(helperText))) { // error text or helper text
-        textPaint.setColor(tempErrorText != null ? errorColor : helperTextColor != -1 ? helperTextColor : (baseColor & 0x00ffffff | 0x44000000));
-        canvas.save();
-        if (isRTL()) {
-          canvas.translate(endX - textLayout.getWidth(), lineStartY + bottomSpacing - bottomTextPadding);
+        int destBottomLines;
+        textPaint.setTextSize(bottomTextSize);
+        if (tempErrorText != null || helperText != null) {
+            Layout.Alignment alignment = (getGravity() & Gravity.RIGHT) == Gravity.RIGHT || isRTL() ?
+                    Layout.Alignment.ALIGN_OPPOSITE : (getGravity() & Gravity.LEFT) == Gravity.LEFT ?
+                    Layout.Alignment.ALIGN_NORMAL : Layout.Alignment.ALIGN_CENTER;
+            textLayout = new StaticLayout(tempErrorText != null ? tempErrorText : helperText, textPaint, getWidth() - getBottomTextLeftOffset() - getBottomTextRightOffset() - getPaddingLeft() - getPaddingRight(), alignment, 1.0f, 0.0f, true);
+            destBottomLines = Math.max(textLayout.getLineCount(), minBottomTextLines);
         } else {
-          canvas.translate(startX + getBottomTextLeftOffset(), lineStartY + bottomSpacing - bottomTextPadding);
+            destBottomLines = minBottomLines;
         }
-        textLayout.draw(canvas);
-        canvas.restore();
-      }
-    }
-
-    // draw the floating label
-    if (floatingLabelEnabled && !TextUtils.isEmpty(floatingLabelText)) {
-      textPaint.setTextSize(floatingLabelTextSize);
-      // calculate the text color
-      textPaint.setColor((Integer) focusEvaluator.evaluate(focusFraction * (isEnabled() ? 1 : 0), floatingLabelTextColor != -1 ? floatingLabelTextColor : (baseColor & 0x00ffffff | 0x44000000), primaryColor));
-
-      // calculate the horizontal position
-      float floatingLabelWidth = textPaint.measureText(floatingLabelText.toString());
-      int floatingLabelStartX;
-      if ((getGravity() & Gravity.RIGHT) == Gravity.RIGHT || isRTL()) {
-        floatingLabelStartX = (int) (endX - floatingLabelWidth);
-      } else if ((getGravity() & Gravity.LEFT) == Gravity.LEFT) {
-        floatingLabelStartX = startX;
-      } else {
-        floatingLabelStartX = startX + (int) (getInnerPaddingLeft() + (getWidth() - getInnerPaddingLeft() - getInnerPaddingRight() - floatingLabelWidth) / 2);
-      }
-
-      // calculate the vertical position
-      int distance = floatingLabelPadding;
-      int floatingLabelStartY = (int) (innerPaddingTop + floatingLabelTextSize + floatingLabelPadding - distance * (floatingLabelAlwaysShown ? 1 : floatingLabelFraction) + getScrollY());
-
-      // calculate the alpha
-      int alpha = ((int) ((floatingLabelAlwaysShown ? 1 : floatingLabelFraction) * 0xff * (0.74f * focusFraction * (isEnabled() ? 1 : 0) + 0.26f) * (floatingLabelTextColor != -1 ? 1 : Color.alpha(floatingLabelTextColor) / 256f)));
-      textPaint.setAlpha(alpha);
-
-      // draw the floating label
-      canvas.drawText(floatingLabelText.toString(), floatingLabelStartX, floatingLabelStartY, textPaint);
-    }
-
-    // draw the bottom ellipsis
-    if (hasFocus() && singleLineEllipsis && getScrollX() != 0) {
-      paint.setColor(isInternalValid() ? primaryColor : errorColor);
-      float startY = lineStartY + bottomSpacing;
-      int ellipsisStartX;
-      if (isRTL()) {
-        ellipsisStartX = endX;
-      } else {
-        ellipsisStartX = startX;
-      }
-      int signum = isRTL() ? -1 : 1;
-      canvas.drawCircle(ellipsisStartX + signum * bottomEllipsisSize / 2, startY + bottomEllipsisSize / 2, bottomEllipsisSize / 2, paint);
-      canvas.drawCircle(ellipsisStartX + signum * bottomEllipsisSize * 5 / 2, startY + bottomEllipsisSize / 2, bottomEllipsisSize / 2, paint);
-      canvas.drawCircle(ellipsisStartX + signum * bottomEllipsisSize * 9 / 2, startY + bottomEllipsisSize / 2, bottomEllipsisSize / 2, paint);
-    }
-
-    // draw the original things
-    super.onDraw(canvas);
-  }
-
-  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-  private boolean isRTL() {
-    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
-      return false;
-    }
-    Configuration config = getResources().getConfiguration();
-    return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-  }
-
-  private int getBottomTextLeftOffset() {
-    return isRTL() ? getCharactersCounterWidth() : getBottomEllipsisWidth();
-  }
-
-  private int getBottomTextRightOffset() {
-    return isRTL() ? getBottomEllipsisWidth() : getCharactersCounterWidth();
-  }
-
-  private int getCharactersCounterWidth() {
-    return hasCharactersCounter() ? (int) textPaint.measureText(getCharactersCounterText()) : 0;
-  }
-
-  private int getBottomEllipsisWidth() {
-    return singleLineEllipsis ? (bottomEllipsisSize * 5 + getPixel(4)) : 0;
-  }
-
-  private void checkCharactersCount() {
-    if ((!firstShown && !checkCharactersCountAtBeginning) || !hasCharactersCounter()) {
-      charactersCountValid = true;
-    } else {
-      CharSequence text = getText();
-      int count = text == null ? 0 : checkLength(text);
-      charactersCountValid = (count >= minCharacters && (maxCharacters <= 0 || count <= maxCharacters));
-    }
-  }
-
-  public boolean isCharactersCountValid() {
-    return charactersCountValid;
-  }
-
-  private boolean hasCharactersCounter() {
-    return minCharacters > 0 || maxCharacters > 0;
-  }
-
-  private String getCharactersCounterText() {
-    String text;
-    if (minCharacters <= 0) {
-      text = isRTL() ? maxCharacters + " / " + checkLength(getText()) : checkLength(getText()) + " / " + maxCharacters;
-    } else if (maxCharacters <= 0) {
-      text = isRTL() ? "+" + minCharacters + " / " + checkLength(getText()) : checkLength(getText()) + " / " + minCharacters + "+";
-    } else {
-      text = isRTL() ? maxCharacters + "-" + minCharacters + " / " + checkLength(getText()) : checkLength(getText()) + " / " + minCharacters + "-" + maxCharacters;
-    }
-    return text;
-  }
-
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    if (singleLineEllipsis && getScrollX() > 0 && event.getAction() == MotionEvent.ACTION_DOWN && event.getX() < getPixel(4 * 5) && event.getY() > getHeight() - extraPaddingBottom - innerPaddingBottom && event.getY() < getHeight() - innerPaddingBottom) {
-      setSelection(0);
-      return false;
-    }
-    if (hasFocus() && showClearButton && isEnabled()) {
-      switch (event.getAction()) {
-        case MotionEvent.ACTION_DOWN:
-          if (insideClearButton(event)) {
-            clearButtonTouched = true;
-            clearButtonClicking = true;
-            return true;
-          }
-        case MotionEvent.ACTION_MOVE:
-          if (clearButtonClicking && !insideClearButton(event)) {
-            clearButtonClicking = false;
-          }
-          if (clearButtonTouched) {
-            return true;
-          }
-          break;
-        case MotionEvent.ACTION_UP:
-          if (clearButtonClicking) {
-            if (!TextUtils.isEmpty(getText())) {
-              setText(null);
+        if (bottomLines != destBottomLines) {
+            getBottomLinesAnimator(destBottomLines).start();
+        }
+        bottomLines = destBottomLines;
+        return true;
+    }
+
+    /**
+     * get inner top padding, not the real paddingTop
+     */
+    public int getInnerPaddingTop() {
+        return innerPaddingTop;
+    }
+
+    /**
+     * get inner bottom padding, not the real paddingBottom
+     */
+    public int getInnerPaddingBottom() {
+        return innerPaddingBottom;
+    }
+
+    /**
+     * get inner left padding, not the real paddingLeft
+     */
+    public int getInnerPaddingLeft() {
+        return innerPaddingLeft;
+    }
+
+    /**
+     * get inner right padding, not the real paddingRight
+     */
+    public int getInnerPaddingRight() {
+        return innerPaddingRight;
+    }
+
+    private void initFloatingLabel() {
+        // observe the text changing
+        addTextChangedListener(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) {
             }
-            clearButtonClicking = false;
-          }
-          if (clearButtonTouched) {
-            clearButtonTouched = false;
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                if (floatingLabelEnabled) {
+                    if (s.length() == 0) {
+                        if (floatingLabelShown) {
+                            floatingLabelShown = false;
+                            getLabelAnimator().reverse();
+                        }
+                    } else if (!floatingLabelShown) {
+                        floatingLabelShown = true;
+                        getLabelAnimator().start();
+                    }
+                }
+            }
+        });
+        // observe the focus state to animate the floating label's text color appropriately
+        innerFocusChangeListener = new OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (floatingLabelEnabled && highlightFloatingLabel) {
+                    if (hasFocus) {
+                        getLabelFocusAnimator().start();
+                    } else {
+                        getLabelFocusAnimator().reverse();
+                    }
+                }
+                if (validateOnFocusLost && !hasFocus) {
+                    validate();
+                }
+                if (outerFocusChangeListener != null) {
+                    outerFocusChangeListener.onFocusChange(v, hasFocus);
+                }
+            }
+        };
+        super.setOnFocusChangeListener(innerFocusChangeListener);
+    }
+
+    public boolean isValidateOnFocusLost() {
+        return validateOnFocusLost;
+    }
+
+    public void setValidateOnFocusLost(boolean validate) {
+        this.validateOnFocusLost = validate;
+    }
+
+    public void setBaseColor(int color) {
+        if (baseColor != color) {
+            baseColor = color;
+        }
+
+        initText();
+
+        postInvalidate();
+    }
+
+    public void setPrimaryColor(int color) {
+        primaryColor = color;
+        postInvalidate();
+    }
+
+    /**
+     * Same function as {@link #setTextColor(int)}. (Directly overriding the built-in one could cause some error, so use this method instead.)
+     */
+    public void setMetTextColor(int color) {
+        textColorStateList = ColorStateList.valueOf(color);
+        resetTextColor();
+    }
+
+    /**
+     * Same function as {@link #setTextColor(ColorStateList)}. (Directly overriding the built-in one could cause some error, so use this method instead.)
+     */
+    public void setMetTextColor(ColorStateList colors) {
+        textColorStateList = colors;
+        resetTextColor();
+    }
+
+    private void resetTextColor() {
+        if (textColorStateList == null) {
+            textColorStateList = new ColorStateList(new int[][]{new int[]{android.R.attr.state_enabled}, EMPTY_STATE_SET}, new int[]{baseColor & 0x00ffffff | 0xdf000000, baseColor & 0x00ffffff | 0x44000000});
+            setTextColor(textColorStateList);
+        } else {
+            setTextColor(textColorStateList);
+        }
+    }
+
+    /**
+     * Same function as {@link #setHintTextColor(int)}. (The built-in one is a final method that can't be overridden, so use this method instead.)
+     */
+    public void setMetHintTextColor(int color) {
+        textColorHintStateList = ColorStateList.valueOf(color);
+        resetHintTextColor();
+    }
+
+    /**
+     * Same function as {@link #setHintTextColor(ColorStateList)}. (The built-in one is a final method that can't be overridden, so use this method instead.)
+     */
+    public void setMetHintTextColor(ColorStateList colors) {
+        textColorHintStateList = colors;
+        resetHintTextColor();
+    }
+
+    private void resetHintTextColor() {
+        if (textColorHintStateList == null) {
+            setHintTextColor(baseColor & 0x00ffffff | 0x44000000);
+        } else {
+            setHintTextColor(textColorHintStateList);
+        }
+    }
+
+    private void setFloatingLabelInternal(int mode) {
+        switch (mode) {
+            case FLOATING_LABEL_NORMAL:
+                floatingLabelEnabled = true;
+                highlightFloatingLabel = false;
+                break;
+            case FLOATING_LABEL_HIGHLIGHT:
+                floatingLabelEnabled = true;
+                highlightFloatingLabel = true;
+                break;
+            default:
+                floatingLabelEnabled = false;
+                highlightFloatingLabel = false;
+                break;
+        }
+    }
+
+    public void setFloatingLabel(@FloatingLabelType int mode) {
+        setFloatingLabelInternal(mode);
+        initPadding();
+    }
+
+    public int getFloatingLabelPadding() {
+        return floatingLabelPadding;
+    }
+
+    public void setFloatingLabelPadding(int padding) {
+        floatingLabelPadding = padding;
+        postInvalidate();
+    }
+
+    public boolean isFloatingLabelAnimating() {
+        return floatingLabelAnimating;
+    }
+
+    public void setFloatingLabelAnimating(boolean animating) {
+        floatingLabelAnimating = animating;
+    }
+
+    public void setSingleLineEllipsis() {
+        setSingleLineEllipsis(true);
+    }
+
+    public void setSingleLineEllipsis(boolean enabled) {
+        singleLineEllipsis = enabled;
+        initMinBottomLines();
+        initPadding();
+        postInvalidate();
+    }
+
+    public int getMaxCharacters() {
+        return maxCharacters;
+    }
+
+    public void setMaxCharacters(int max) {
+        maxCharacters = max;
+        initMinBottomLines();
+        initPadding();
+        postInvalidate();
+    }
+
+    public int getMinCharacters() {
+        return minCharacters;
+    }
+
+    public void setMinCharacters(int min) {
+        minCharacters = min;
+        initMinBottomLines();
+        initPadding();
+        postInvalidate();
+    }
+
+    public int getMinBottomTextLines() {
+        return minBottomTextLines;
+    }
+
+    public void setMinBottomTextLines(int lines) {
+        minBottomTextLines = lines;
+        initMinBottomLines();
+        initPadding();
+        postInvalidate();
+    }
+
+    public boolean isAutoValidate() {
+        return autoValidate;
+    }
+
+    public void setAutoValidate(boolean autoValidate) {
+        this.autoValidate = autoValidate;
+        if (autoValidate) {
+            validate();
+        }
+    }
+
+    public int getErrorColor() {
+        return errorColor;
+    }
+
+    public void setErrorColor(int color) {
+        errorColor = color;
+        postInvalidate();
+    }
+
+    public void setHelperText(CharSequence helperText) {
+        this.helperText = helperText == null ? null : helperText.toString();
+        if (adjustBottomLines()) {
+            postInvalidate();
+        }
+    }
+
+    public String getHelperText() {
+        return helperText;
+    }
+
+    public int getHelperTextColor() {
+        return helperTextColor;
+    }
+
+    public void setHelperTextColor(int color) {
+        helperTextColor = color;
+        postInvalidate();
+    }
+
+    @Override
+    public void setError(CharSequence errorText) {
+        tempErrorText = errorText == null ? null : errorText.toString();
+        if (adjustBottomLines()) {
+            postInvalidate();
+        }
+    }
+
+    @Override
+    public CharSequence getError() {
+        return tempErrorText;
+    }
+
+    /**
+     * only used to draw the bottom line
+     */
+    private boolean isInternalValid() {
+        return tempErrorText == null && isCharactersCountValid();
+    }
+
+    /**
+     * if the main text matches the regex
+     *
+     * @deprecated use the new validator interface to add your own custom validator
+     */
+    @Deprecated
+    public boolean isValid(String regex) {
+        if (regex == null) {
+            return false;
+        }
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(getText());
+        return matcher.matches();
+    }
+
+    /**
+     * check if the main text matches the regex, and set the error text if not.
+     *
+     * @return true if it matches the regex, false if not.
+     * @deprecated use the new validator interface to add your own custom validator
+     */
+    @Deprecated
+    public boolean validate(String regex, CharSequence errorText) {
+        boolean isValid = isValid(regex);
+        if (!isValid) {
+            setError(errorText);
+        }
+        postInvalidate();
+        return isValid;
+    }
+
+    /**
+     * Run validation on a single validator instance
+     *
+     * @param validator Validator to check
+     * @return True if valid, false if not
+     */
+    public boolean validateWith(@NonNull METValidator validator) {
+        CharSequence text = getText();
+        boolean isValid = validator.isValid(text, text.length() == 0);
+        if (!isValid) {
+            setError(validator.getErrorMessage());
+        }
+        postInvalidate();
+        return isValid;
+    }
+
+    /**
+     * Check all validators, sets the error text if not
+     * <p/>
+     * NOTE: this stops at the first validator to report invalid.
+     *
+     * @return True if all validators pass, false if not
+     */
+    public boolean validate() {
+        if (validators == null || validators.isEmpty()) {
             return true;
-          }
-          clearButtonTouched = false;
-          break;
-        case MotionEvent.ACTION_CANCEL:
-          clearButtonTouched = false;
-          clearButtonClicking = false;
-          break;
-      }
-    }
-    return super.onTouchEvent(event);
-  }
-
-  private boolean insideClearButton(MotionEvent event) {
-    float x = event.getX();
-    float y = event.getY();
-    int startX = getScrollX() + (iconLeftBitmaps == null ? 0 : (iconOuterWidth + iconPadding));
-    int endX = getScrollX() + (iconRightBitmaps == null ? getWidth() : getWidth() - iconOuterWidth - iconPadding);
-    int buttonLeft;
-    if (isRTL()) {
-      buttonLeft = startX;
-    } else {
-      buttonLeft = endX - iconOuterWidth;
-    }
-    int buttonTop = getScrollY() + getHeight() - getPaddingBottom() + bottomSpacing - iconOuterHeight;
-    return (x >= buttonLeft && x < buttonLeft + iconOuterWidth && y >= buttonTop && y < buttonTop + iconOuterHeight);
-  }
-
-  private int checkLength(CharSequence text) {
-    if (lengthChecker==null) return text.length();
-    return lengthChecker.getLength(text);
-  }
+        }
+
+        CharSequence text = getText();
+        boolean isEmpty = text.length() == 0;
+
+        boolean isValid = true;
+        for (METValidator validator : validators) {
+            //noinspection ConstantConditions
+            isValid = isValid && validator.isValid(text, isEmpty);
+            if (!isValid) {
+                setError(validator.getErrorMessage());
+                break;
+            }
+        }
+        if (isValid) {
+            setError(null);
+        }
+
+        postInvalidate();
+        return isValid;
+    }
+
+    public boolean hasValidators() {
+        return this.validators != null && !this.validators.isEmpty();
+    }
+
+    /**
+     * Adds a new validator to the View's list of validators
+     * <p/>
+     * This will be checked with the others in {@link #validate()}
+     *
+     * @param validator Validator to add
+     * @return This instance, for easy chaining
+     */
+    public MaterialEditText addValidator(METValidator validator) {
+        if (validators == null) {
+            this.validators = new ArrayList<>();
+        }
+        this.validators.add(validator);
+        return this;
+    }
+
+    public void clearValidators() {
+        if (this.validators != null) {
+            this.validators.clear();
+        }
+    }
+
+    @Nullable
+    public List<METValidator> getValidators() {
+        return this.validators;
+    }
+
+    public void setLengthChecker(METLengthChecker lengthChecker) {
+        this.lengthChecker = lengthChecker;
+    }
+
+    @Override
+    public void setOnFocusChangeListener(OnFocusChangeListener listener) {
+        if (innerFocusChangeListener == null) {
+            super.setOnFocusChangeListener(listener);
+        } else {
+            outerFocusChangeListener = listener;
+        }
+    }
+
+    private ObjectAnimator getLabelAnimator() {
+        if (labelAnimator == null) {
+            labelAnimator = ObjectAnimator.ofFloat(this, "floatingLabelFraction", 0f, 1f);
+        }
+        labelAnimator.setDuration(floatingLabelAnimating ? 300 : 0);
+        return labelAnimator;
+    }
+
+    private ObjectAnimator getLabelFocusAnimator() {
+        if (labelFocusAnimator == null) {
+            labelFocusAnimator = ObjectAnimator.ofFloat(this, "focusFraction", 0f, 1f);
+        }
+        return labelFocusAnimator;
+    }
+
+    private ObjectAnimator getBottomLinesAnimator(float destBottomLines) {
+        if (bottomLinesAnimator == null) {
+            bottomLinesAnimator = ObjectAnimator.ofFloat(this, "currentBottomLines", destBottomLines);
+        } else {
+            bottomLinesAnimator.cancel();
+            bottomLinesAnimator.setFloatValues(destBottomLines);
+        }
+        return bottomLinesAnimator;
+    }
+
+    @Override
+    protected void onDraw(@NonNull Canvas canvas) {
+
+        int startX = getScrollX() + (iconLeftBitmaps == null ? 0 : (iconOuterWidth + iconPadding)) + getPaddingLeft();
+        int endX = getScrollX() + (iconRightBitmaps == null ? getWidth() : getWidth() - iconOuterWidth - iconPadding) - getPaddingRight();
+        int lineStartY = getScrollY() + getHeight() - getPaddingBottom();
+
+        // draw the icon(s)
+        paint.setAlpha(255);
+        if (iconLeftBitmaps != null) {
+            Bitmap icon = iconLeftBitmaps[!isInternalValid() ? 3 : !isEnabled() ? 2 : hasFocus() ? 1 : 0];
+            int iconLeft = startX - iconPadding - iconOuterWidth + (iconOuterWidth - icon.getWidth()) / 2;
+            int iconTop = lineStartY + bottomSpacing - iconOuterHeight + (iconOuterHeight - icon.getHeight()) / 2;
+            canvas.drawBitmap(icon, iconLeft, iconTop, paint);
+        }
+        if (iconRightBitmaps != null) {
+            Bitmap icon = iconRightBitmaps[!isInternalValid() ? 3 : !isEnabled() ? 2 : hasFocus() ? 1 : 0];
+            int iconRight = endX + iconPadding + (iconOuterWidth - icon.getWidth()) / 2;
+            int iconTop = lineStartY + bottomSpacing - iconOuterHeight + (iconOuterHeight - icon.getHeight()) / 2;
+            canvas.drawBitmap(icon, iconRight, iconTop, paint);
+        }
+
+        // draw the clear button
+        if (hasFocus() && showClearButton && !TextUtils.isEmpty(getText()) && isEnabled()) {
+            paint.setAlpha(255);
+            int buttonLeft;
+            if (isRTL()) {
+                buttonLeft = startX;
+            } else {
+                buttonLeft = endX - iconOuterWidth;
+            }
+            Bitmap clearButtonBitmap = clearButtonBitmaps[0];
+            buttonLeft += (iconOuterWidth - clearButtonBitmap.getWidth()) / 2;
+            int iconTop = lineStartY + bottomSpacing - iconOuterHeight + (iconOuterHeight - clearButtonBitmap.getHeight()) / 2;
+            canvas.drawBitmap(clearButtonBitmap, buttonLeft, iconTop, paint);
+        }
+
+        // draw the underline
+        if (!hideUnderline) {
+            lineStartY += bottomSpacing;
+            if (!isInternalValid()) { // not valid
+                paint.setColor(errorColor);
+                canvas.drawRect(startX, lineStartY, endX, lineStartY + getPixel(2), paint);
+            } else if (!isEnabled()) { // disabled
+
+
+
+                int disabledLineColor = disabledUnderlineColor;
+                if (disabledUnderlineColor == -1){
+                    disabledLineColor = underlineColor != -1 ? underlineColor : baseColor;
+                }
+                paint.setColor(disabledLineColor & 0x00ffffff | 0x44000000);
+                if (dottedBottomLinesForDisabledState){
+                    float interval = getPixel(1);
+                    for (float xOffset = 0; xOffset < getWidth(); xOffset += interval * 3) {
+                        canvas.drawRect(startX + xOffset, lineStartY, startX + xOffset + interval, lineStartY + getPixel(1), paint);
+                    }
+                }
+                else{
+                    canvas.drawRect(startX, lineStartY, endX, lineStartY + getPixel(1), paint);
+                }
+            } else if (hasFocus()) { // focused
+                paint.setColor(primaryColor);
+                canvas.drawRect(startX, lineStartY, endX, lineStartY + getPixel(2), paint);
+            } else { // normal
+                paint.setColor(underlineColor != -1 ? underlineColor : baseColor & 0x00ffffff | 0x1E000000);
+                canvas.drawRect(startX, lineStartY, endX, lineStartY + getPixel(1), paint);
+            }
+        }
+
+        textPaint.setTextSize(bottomTextSize);
+        Paint.FontMetrics textMetrics = textPaint.getFontMetrics();
+        float relativeHeight = -textMetrics.ascent - textMetrics.descent;
+        float bottomTextPadding = bottomTextSize + textMetrics.ascent + textMetrics.descent;
+
+        // draw the characters counter
+        if ((hasFocus() && hasCharactersCounter()) || !isCharactersCountValid()) {
+            textPaint.setColor(isCharactersCountValid() ? (baseColor & 0x00ffffff | 0x44000000) : errorColor);
+            String charactersCounterText = getCharactersCounterText();
+            canvas.drawText(charactersCounterText, isRTL() ? startX : endX - textPaint.measureText(charactersCounterText), lineStartY + bottomSpacing + relativeHeight, textPaint);
+        }
+
+        // draw the bottom text
+        if (textLayout != null) {
+            if (tempErrorText != null || ((helperTextAlwaysShown || hasFocus()) && !TextUtils.isEmpty(helperText))) { // error text or helper text
+                textPaint.setColor(tempErrorText != null ? errorColor : helperTextColor != -1 ? helperTextColor : (baseColor & 0x00ffffff | 0x44000000));
+                canvas.save();
+                if (isRTL()) {
+                    canvas.translate(endX - textLayout.getWidth(), lineStartY + bottomSpacing - bottomTextPadding);
+                } else {
+                    canvas.translate(startX + getBottomTextLeftOffset(), lineStartY + bottomSpacing - bottomTextPadding);
+                }
+                textLayout.draw(canvas);
+                canvas.restore();
+            }
+        }
+
+        // draw the floating label
+        if (floatingLabelEnabled && !TextUtils.isEmpty(floatingLabelText)) {
+            textPaint.setTextSize(floatingLabelTextSize);
+            // calculate the text color
+            textPaint.setColor((Integer) focusEvaluator.evaluate(focusFraction * (isEnabled() ? 1 : 0), floatingLabelTextColor != -1 ? floatingLabelTextColor : (baseColor & 0x00ffffff | 0x44000000), primaryColor));
+
+            // calculate the horizontal position
+            float floatingLabelWidth = textPaint.measureText(floatingLabelText.toString());
+            int floatingLabelStartX;
+            if ((getGravity() & Gravity.RIGHT) == Gravity.RIGHT || isRTL()) {
+                floatingLabelStartX = (int) (endX - floatingLabelWidth);
+            } else if ((getGravity() & Gravity.LEFT) == Gravity.LEFT) {
+                floatingLabelStartX = startX;
+            } else {
+                floatingLabelStartX = startX + (int) (getInnerPaddingLeft() + (getWidth() - getInnerPaddingLeft() - getInnerPaddingRight() - floatingLabelWidth) / 2);
+            }
+
+            // calculate the vertical position
+            int distance = floatingLabelPadding;
+            int floatingLabelStartY = (int) (innerPaddingTop + floatingLabelTextSize + floatingLabelPadding - distance * (floatingLabelAlwaysShown ? 1 : floatingLabelFraction) + getScrollY());
+
+            // calculate the alpha
+            int alpha = ((int) ((floatingLabelAlwaysShown ? 1 : floatingLabelFraction) * 0xff * (0.74f * focusFraction * (isEnabled() ? 1 : 0) + 0.26f) * (floatingLabelTextColor != -1 ? 1 : Color.alpha(floatingLabelTextColor) / 256f)));
+            textPaint.setAlpha(alpha);
+
+            // draw the floating label
+            canvas.drawText(floatingLabelText.toString(), floatingLabelStartX, floatingLabelStartY, textPaint);
+        }
+
+        // draw the bottom ellipsis
+        if (hasFocus() && singleLineEllipsis && getScrollX() != 0) {
+            paint.setColor(isInternalValid() ? primaryColor : errorColor);
+            float startY = lineStartY + bottomSpacing;
+            int ellipsisStartX;
+            if (isRTL()) {
+                ellipsisStartX = endX;
+            } else {
+                ellipsisStartX = startX;
+            }
+            int signum = isRTL() ? -1 : 1;
+            canvas.drawCircle(ellipsisStartX + signum * bottomEllipsisSize / 2, startY + bottomEllipsisSize / 2, bottomEllipsisSize / 2, paint);
+            canvas.drawCircle(ellipsisStartX + signum * bottomEllipsisSize * 5 / 2, startY + bottomEllipsisSize / 2, bottomEllipsisSize / 2, paint);
+            canvas.drawCircle(ellipsisStartX + signum * bottomEllipsisSize * 9 / 2, startY + bottomEllipsisSize / 2, bottomEllipsisSize / 2, paint);
+        }
+
+        // draw the original things
+        super.onDraw(canvas);
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    private boolean isRTL() {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return false;
+        }
+        Configuration config = getResources().getConfiguration();
+        return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+    }
+
+    private int getBottomTextLeftOffset() {
+        return isRTL() ? getCharactersCounterWidth() : getBottomEllipsisWidth();
+    }
+
+    private int getBottomTextRightOffset() {
+        return isRTL() ? getBottomEllipsisWidth() : getCharactersCounterWidth();
+    }
+
+    private int getCharactersCounterWidth() {
+        return hasCharactersCounter() ? (int) textPaint.measureText(getCharactersCounterText()) : 0;
+    }
+
+    private int getBottomEllipsisWidth() {
+        return singleLineEllipsis ? (bottomEllipsisSize * 5 + getPixel(4)) : 0;
+    }
+
+    private void checkCharactersCount() {
+        if ((!firstShown && !checkCharactersCountAtBeginning) || !hasCharactersCounter()) {
+            charactersCountValid = true;
+        } else {
+            CharSequence text = getText();
+            int count = text == null ? 0 : checkLength(text);
+            charactersCountValid = (count >= minCharacters && (maxCharacters <= 0 || count <= maxCharacters));
+        }
+    }
+
+    public boolean isCharactersCountValid() {
+        return charactersCountValid;
+    }
+
+    private boolean hasCharactersCounter() {
+        return minCharacters > 0 || maxCharacters > 0;
+    }
+
+    private String getCharactersCounterText() {
+        String text;
+        if (minCharacters <= 0) {
+            text = isRTL() ? maxCharacters + " / " + checkLength(getText()) : checkLength(getText()) + " / " + maxCharacters;
+        } else if (maxCharacters <= 0) {
+            text = isRTL() ? "+" + minCharacters + " / " + checkLength(getText()) : checkLength(getText()) + " / " + minCharacters + "+";
+        } else {
+            text = isRTL() ? maxCharacters + "-" + minCharacters + " / " + checkLength(getText()) : checkLength(getText()) + " / " + minCharacters + "-" + maxCharacters;
+        }
+        return text;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (singleLineEllipsis && getScrollX() > 0 && event.getAction() == MotionEvent.ACTION_DOWN && event.getX() < getPixel(4 * 5) && event.getY() > getHeight() - extraPaddingBottom - innerPaddingBottom && event.getY() < getHeight() - innerPaddingBottom) {
+            setSelection(0);
+            return false;
+        }
+        if (hasFocus() && showClearButton && isEnabled()) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    if (insideClearButton(event)) {
+                        clearButtonTouched = true;
+                        clearButtonClicking = true;
+                        return true;
+                    }
+                case MotionEvent.ACTION_MOVE:
+                    if (clearButtonClicking && !insideClearButton(event)) {
+                        clearButtonClicking = false;
+                    }
+                    if (clearButtonTouched) {
+                        return true;
+                    }
+                    break;
+                case MotionEvent.ACTION_UP:
+                    if (clearButtonClicking) {
+                        if (!TextUtils.isEmpty(getText())) {
+                            setText(null);
+                        }
+                        clearButtonClicking = false;
+                    }
+                    if (clearButtonTouched) {
+                        clearButtonTouched = false;
+                        return true;
+                    }
+                    clearButtonTouched = false;
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                    clearButtonTouched = false;
+                    clearButtonClicking = false;
+                    break;
+            }
+        }
+        return super.onTouchEvent(event);
+    }
+
+    private boolean insideClearButton(MotionEvent event) {
+        float x = event.getX();
+        float y = event.getY();
+        int startX = getScrollX() + (iconLeftBitmaps == null ? 0 : (iconOuterWidth + iconPadding));
+        int endX = getScrollX() + (iconRightBitmaps == null ? getWidth() : getWidth() - iconOuterWidth - iconPadding);
+        int buttonLeft;
+        if (isRTL()) {
+            buttonLeft = startX;
+        } else {
+            buttonLeft = endX - iconOuterWidth;
+        }
+        int buttonTop = getScrollY() + getHeight() - getPaddingBottom() + bottomSpacing - iconOuterHeight;
+        return (x >= buttonLeft && x < buttonLeft + iconOuterWidth && y >= buttonTop && y < buttonTop + iconOuterHeight);
+    }
+
+    private int checkLength(CharSequence text) {
+        if (lengthChecker == null) return text.length();
+        return lengthChecker.getLength(text);
+    }
 }
\ No newline at end of file
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
index ce50f9a2..196e0b41 100644
--- a/library/src/main/res/values/attrs.xml
+++ b/library/src/main/res/values/attrs.xml
@@ -17,6 +17,10 @@
     <attr name="met_minCharacters" format="integer" />
     <!-- max Characters count limit. 0 means no limit. -->
     <attr name="met_maxCharacters" format="integer" />
+    <!-- If disabled, then the bottom line is dotted if true.  Defaults to true. -->
+    <attr name="met_disabledBottomLineDotted" format="boolean" />
+    <!-- The color for when something is wrong.(e.g. exceeding max characters) -->
+    <attr name="met_disabledBottomLineColor" format="color" />
     <!-- Whether to show the bottom ellipsis in singleLine mode -->
     <attr name="met_singleLineEllipsis" format="boolean" />
     <!-- Reserved bottom text lines count, no matter if there is some helper/error text. -->
diff --git a/sample/src/main/java/com/rengwuxian/materialedittext/sample/MainActivity.java b/sample/src/main/java/com/rengwuxian/materialedittext/sample/MainActivity.java
index 693d8e3f..3a771168 100644
--- a/sample/src/main/java/com/rengwuxian/materialedittext/sample/MainActivity.java
+++ b/sample/src/main/java/com/rengwuxian/materialedittext/sample/MainActivity.java
@@ -24,7 +24,10 @@ protected void onCreate(Bundle savedInstanceState) {
 		initSingleLineEllipsisEt();
 		initSetErrorEt();
 		initValidationEt();
-  }
+
+		findViewById(R.id.disabledSolidLine).setEnabled(false);
+
+	}
 
 	private void initEnableBt() {
 		final EditText basicEt = (EditText) findViewById(R.id.basicEt);
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
index 4c45dc19..ade204ed 100644
--- a/sample/src/main/res/layout/activity_main.xml
+++ b/sample/src/main/res/layout/activity_main.xml
@@ -1,434 +1,443 @@
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-  xmlns:app="http://schemas.android.com/apk/res-auto"
-  xmlns:tools="http://schemas.android.com/tools"
-  android:layout_width="match_parent"
-  android:layout_height="match_parent"
-  android:scrollbarStyle="outsideOverlay"
-  tools:context=".MainActivity">
-
-  <LinearLayout
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
+    android:layout_height="match_parent"
+    android:scrollbarStyle="outsideOverlay"
+    tools:context=".MainActivity">
 
     <LinearLayout
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:background="?colorPrimary"
-      android:orientation="vertical"
-      android:paddingBottom="16dp"
-      android:paddingLeft="72dp"
-      android:paddingRight="16dp"
-      android:paddingTop="16dp">
-
-      <com.rengwuxian.materialedittext.MaterialEditText
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:hint="Library Name"
-        android:text="MaterialEditText"
-        android:textCursorDrawable="@drawable/text_cursor_cyan"
-        android:textSize="34sp"
-        app:met_baseColor="@android:color/white"
-        app:met_floatingLabel="highlight"
-        app:met_maxCharacters="20"
-        app:met_primaryColor="?colorAccent"
-        app:met_singleLineEllipsis="true" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Description"
-        android:text="EditText in Material Design"
-        android:textCursorDrawable="@drawable/text_cursor_cyan"
-        app:met_baseColor="@android:color/white"
-        app:met_floatingLabel="highlight"
-        app:met_maxCharacters="20"
-        app:met_primaryColor="?colorAccent" />
-
-    </LinearLayout>
-
-    <LinearLayout
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical"
-      android:paddingBottom="@dimen/activity_vertical_margin"
-      android:paddingLeft="@dimen/activity_horizontal_margin"
-      android:paddingRight="@dimen/activity_horizontal_margin"
-      android:paddingTop="@dimen/activity_vertical_margin">
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="Basic:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical">
-
-        <com.rengwuxian.materialedittext.MaterialEditText
-          android:id="@+id/basicEt"
-          android:layout_width="0dp"
-          android:layout_height="wrap_content"
-          android:layout_weight="1"
-          android:hint="Basic"
-          android:textColor="@color/text_color"/>
-
-        <Button
-          android:id="@+id/enableBt"
-          android:layout_width="100dp"
-          android:layout_height="wrap_content"
-          android:layout_marginLeft="8dp"
-          android:text="DISABLE" />
-
-      </LinearLayout>
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Floating Label:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_floatingLabel=&quot;normal&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Floating Label"
-        app:met_floatingLabel="normal" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Highlight Floating Label:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_floatingLabel=&quot;highlight&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Highlight Floating Label"
-        app:met_floatingLabel="highlight"/>
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Custom Floating Label Text:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_floatingLabel=&quot;normal&quot;\napp:met_floatingLabelText=&quot;Label&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Custom Floating Label Text"
-        app:met_floatingLabel="normal"
-        app:met_floatingLabelText="Label" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Single Line Ellipsis:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_singleLineEllipsis=&quot;true&quot;\n#singLineEllipsis will force android:singleLine to true#"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:id="@+id/singleLineEllipsisEt"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Single Line Ellipsis"
-        android:text="Touch The Ellipsis And See What Happens. Touch The Ellipsis And See What Happens."
-        app:met_singleLineEllipsis="true" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Max/Min Characters:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_maxCharacters=&quot;5&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Max Characters"
-        app:met_maxCharacters="5" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_minCharacters=&quot;3&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Min Characters"
-        app:met_minCharacters="3" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_minCharacters=&quot;3&quot;\napp:met_maxCharacters=&quot;5&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Min and Max"
-        app:met_maxCharacters="5"
-        app:met_minCharacters="3" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Helper/Error Text:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_helperText=&quot;helper is here&quot; (in xml)\nsetError(&quot;Error!&quot;) (in java)"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical">
-
-        <com.rengwuxian.materialedittext.MaterialEditText
-          android:id="@+id/bottomTextEt"
-          android:layout_width="0dp"
-          android:layout_height="wrap_content"
-          android:layout_weight="1"
-          android:hint="Helper/Error Text"
-          app:met_helperText="helper is here" />
-
-        <Button
-          android:id="@+id/setErrorBt"
-          android:layout_width="48dp"
-          android:layout_height="wrap_content"
-          android:layout_marginLeft="8dp"
-          android:text="1" />
-
-        <Button
-          android:id="@+id/setError2Bt"
-          android:layout_width="48dp"
-          android:layout_height="wrap_content"
-          android:layout_marginLeft="8dp"
-          android:text="2" />
-
-        <Button
-          android:id="@+id/setError3Bt"
-          android:layout_width="48dp"
-          android:layout_height="wrap_content"
-          android:layout_marginLeft="8dp"
-          android:text="3" />
-
-      </LinearLayout>
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Validation:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="addValidator(new RegexValidator(&quot;Only Integer Valid!&quot;, &quot;\\\\d+&quot;)); (in java)"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical">
-
-        <com.rengwuxian.materialedittext.MaterialEditText
-          android:id="@+id/validationEt"
-          android:layout_width="0dp"
-          android:layout_height="wrap_content"
-          android:layout_weight="1"
-          android:hint="Validation"
-          app:met_helperText="Integer" />
-
-        <Button
-          android:id="@+id/validateBt"
-          android:layout_width="120dp"
-          android:layout_height="wrap_content"
-          android:layout_marginLeft="8dp"
-          android:text="VALIDATE" />
-
-      </LinearLayout>
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Custom Colors:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_baseColor=&quot;#007688&quot;\napp:met_primaryColor=&quot;#2196F3&quot;\napp:met_textColor=&quot;@color/text_color&quot;\napp:met_textColorHint=&quot;#33ff0000&quot;\napp:met_errorColor=&quot;#ddaa00&quot;\napp:met_helperTextColor=&quot;#795548&quot;\napp:met_underlineColor=&quot;#003587&quot;\napp:met_floatingLabelTextColor=&quot;#8805ad&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Custom Colors"
-        app:met_floatingLabel="normal"
-        app:met_helperText="Helper Text"
-        app:met_maxCharacters="5"
-        app:met_baseColor="#007688"
-        app:met_primaryColor="#2196F3"
-        app:met_textColor="@color/text_color"
-        app:met_textColorHint="#33ff0000"
-        app:met_errorColor="#ddaa00"
-        app:met_helperTextColor="#795548"
-        app:met_underlineColor="#003587"
-        app:met_floatingLabelTextColor="#8805ad"/>
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Custom Typeface:"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_typeface=&quot;fonts/Roboto-LightItalic.ttf&quot;\napp:met_accentTypeface=&quot;fonts/Roboto-LightItalic.ttf&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Custom Accent Typeface"
-        app:met_typeface="fonts/Roboto-LightItalic.ttf"
-        app:met_accentTypeface="fonts/Roboto-LightItalic.ttf"
-        app:met_floatingLabel="normal"
-        app:met_helperText="Helper Text"
-        app:met_maxCharacters="5" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Hide underline"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_hideUnderline=&quot;true&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Hidden underline"
-        app:met_hideUnderline="true" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Clear Button"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_clearButton=&quot;true&quot;"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Clear Button"
-        app:met_clearButton="true" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="Material Design Icon"
-        android:textColor="#333333"
-        android:textSize="14sp" />
-
-      <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="app:met_iconLeft=&quot;@drawable/ic_phone&quot;\napp:met_iconPadding=&quot;0dp&quot; (Note: 16dp by default, not 0)"
-        android:textColor="#888888"
-        android:textSize="14sp" />
-
-      <com.rengwuxian.materialedittext.MaterialEditText
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="Material Design Icon"
-        app:met_iconLeft="@drawable/ic_phone"
-        app:met_iconPadding="0dp"
-        app:met_maxCharacters="5" />
-
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="?colorPrimary"
+            android:orientation="vertical"
+            android:paddingBottom="16dp"
+            android:paddingLeft="72dp"
+            android:paddingRight="16dp"
+            android:paddingTop="16dp">
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Library Name"
+                android:text="MaterialEditText"
+                android:textCursorDrawable="@drawable/text_cursor_cyan"
+                android:textSize="34sp"
+                app:met_baseColor="@android:color/white"
+                app:met_floatingLabel="highlight"
+                app:met_maxCharacters="20"
+                app:met_primaryColor="?colorAccent"
+                app:met_singleLineEllipsis="true" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Description"
+                android:text="EditText in Material Design"
+                android:textCursorDrawable="@drawable/text_cursor_cyan"
+                app:met_baseColor="@android:color/white"
+                app:met_floatingLabel="highlight"
+                app:met_maxCharacters="20"
+                app:met_primaryColor="?colorAccent" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingBottom="@dimen/activity_vertical_margin"
+            android:paddingLeft="@dimen/activity_horizontal_margin"
+            android:paddingRight="@dimen/activity_horizontal_margin"
+            android:paddingTop="@dimen/activity_vertical_margin">
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="Basic:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical">
+
+                <com.rengwuxian.materialedittext.MaterialEditText
+                    android:id="@+id/basicEt"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:hint="Basic"
+                    android:textColor="@color/text_color" />
+
+                <Button
+                    android:id="@+id/enableBt"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="8dp"
+                    android:text="DISABLE" />
+
+            </LinearLayout>
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Floating Label:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_floatingLabel=&quot;normal&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Floating Label"
+                app:met_floatingLabel="normal" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Highlight Floating Label:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_floatingLabel=&quot;highlight&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Highlight Floating Label"
+                app:met_floatingLabel="highlight" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Custom Floating Label Text:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_floatingLabel=&quot;normal&quot;\napp:met_floatingLabelText=&quot;Label&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Custom Floating Label Text"
+                app:met_floatingLabel="normal"
+                app:met_floatingLabelText="Label" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Single Line Ellipsis:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_singleLineEllipsis=&quot;true&quot;\n#singLineEllipsis will force android:singleLine to true#"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:id="@+id/singleLineEllipsisEt"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Single Line Ellipsis"
+                android:text="Touch The Ellipsis And See What Happens. Touch The Ellipsis And See What Happens."
+                app:met_singleLineEllipsis="true" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Max/Min Characters:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_maxCharacters=&quot;5&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Max Characters"
+                app:met_maxCharacters="5" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_minCharacters=&quot;3&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Min Characters"
+                app:met_minCharacters="3" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_minCharacters=&quot;3&quot;\napp:met_maxCharacters=&quot;5&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Min and Max"
+                app:met_maxCharacters="5"
+                app:met_minCharacters="3" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Helper/Error Text:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_helperText=&quot;helper is here&quot; (in xml)\nsetError(&quot;Error!&quot;) (in java)"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical">
+
+                <com.rengwuxian.materialedittext.MaterialEditText
+                    android:id="@+id/bottomTextEt"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:hint="Helper/Error Text"
+                    app:met_helperText="helper is here" />
+
+                <Button
+                    android:id="@+id/setErrorBt"
+                    android:layout_width="48dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="8dp"
+                    android:text="1" />
+
+                <Button
+                    android:id="@+id/setError2Bt"
+                    android:layout_width="48dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="8dp"
+                    android:text="2" />
+
+                <Button
+                    android:id="@+id/setError3Bt"
+                    android:layout_width="48dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="8dp"
+                    android:text="3" />
+
+            </LinearLayout>
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Validation:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="addValidator(new RegexValidator(&quot;Only Integer Valid!&quot;, &quot;\\\\d+&quot;)); (in java)"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical">
+
+                <com.rengwuxian.materialedittext.MaterialEditText
+                    android:id="@+id/validationEt"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:hint="Validation"
+                    app:met_helperText="Integer" />
+
+                <Button
+                    android:id="@+id/validateBt"
+                    android:layout_width="120dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="8dp"
+                    android:text="VALIDATE" />
+
+            </LinearLayout>
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Custom Colors:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_baseColor=&quot;#007688&quot;\napp:met_primaryColor=&quot;#2196F3&quot;\napp:met_textColor=&quot;@color/text_color&quot;\napp:met_textColorHint=&quot;#33ff0000&quot;\napp:met_errorColor=&quot;#ddaa00&quot;\napp:met_helperTextColor=&quot;#795548&quot;\napp:met_underlineColor=&quot;#003587&quot;\napp:met_floatingLabelTextColor=&quot;#8805ad&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Custom Colors"
+                app:met_baseColor="#007688"
+                app:met_errorColor="#ddaa00"
+                app:met_floatingLabel="normal"
+                app:met_floatingLabelTextColor="#8805ad"
+                app:met_helperText="Helper Text"
+                app:met_helperTextColor="#795548"
+                app:met_maxCharacters="5"
+                app:met_primaryColor="#2196F3"
+                app:met_textColor="@color/text_color"
+                app:met_textColorHint="#33ff0000"
+                app:met_underlineColor="#003587" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Custom Typeface:"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_typeface=&quot;fonts/Roboto-LightItalic.ttf&quot;\napp:met_accentTypeface=&quot;fonts/Roboto-LightItalic.ttf&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Custom Accent Typeface"
+                app:met_accentTypeface="fonts/Roboto-LightItalic.ttf"
+                app:met_floatingLabel="normal"
+                app:met_helperText="Helper Text"
+                app:met_maxCharacters="5"
+                app:met_typeface="fonts/Roboto-LightItalic.ttf" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Hide underline"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_hideUnderline=&quot;true&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Hidden underline"
+                app:met_hideUnderline="true" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Clear Button"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_clearButton=&quot;true&quot;"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Clear Button"
+                app:met_clearButton="true" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:text="Material Design Icon"
+                android:textColor="#333333"
+                android:textSize="14sp" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="app:met_iconLeft=&quot;@drawable/ic_phone&quot;\napp:met_iconPadding=&quot;0dp&quot; (Note: 16dp by default, not 0)"
+                android:textColor="#888888"
+                android:textSize="14sp" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Material Design Icon"
+                app:met_iconLeft="@drawable/ic_phone"
+                app:met_iconPadding="0dp"
+                app:met_maxCharacters="5" />
+
+            <com.rengwuxian.materialedittext.MaterialEditText
+                android:id="@+id/disabledSolidLine"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="Solid line disabled color"
+                android:text="This is disabled and still shows a solid line."
+                app:met_disabledBottomLineColor="#33ff0000"
+                app:met_disabledBottomLineDotted="false" />
+
+        </LinearLayout>
     </LinearLayout>
-  </LinearLayout>
 </ScrollView>
\ No newline at end of file