Skip to content

Instantly share code, notes, and snippets.

@slightfoot
Last active May 12, 2022 08:11

Revisions

  1. Simon Lightfoot renamed this gist May 30, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. Simon Lightfoot created this gist May 30, 2015.
    80 changes: 80 additions & 0 deletions CharacterCountErrorWatcher.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    import android.graphics.Color;
    import android.support.design.widget.TextInputLayout;
    import android.text.Editable;
    import android.text.Layout;
    import android.text.SpannableStringBuilder;
    import android.text.Spanned;
    import android.text.TextWatcher;
    import android.text.style.AlignmentSpan;
    import android.text.style.ForegroundColorSpan;


    /**
    * Material Design Guidlines:
    * http://www.google.com/design/spec/patterns/errors.html#errors-user-input-errors
    * see section headed "Text field input - Over/under character or word count"
    *
    * @author Simon Lightfoot <[email protected]>
    */
    public class CharacterCountErrorWatcher
    implements TextWatcher
    {
    private final TextInputLayout mTextInputLayout;
    private final ForegroundColorSpan mNormalTextAppearance;
    private final AlignmentSpan mAlignmentSpan = new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE);
    private final SpannableStringBuilder mErrorText = new SpannableStringBuilder();
    private int mMinLen;
    private int mMaxLen;

    public CharacterCountErrorWatcher(TextInputLayout textInputLayout, int minLen, int maxLen)
    {
    mTextInputLayout = textInputLayout;
    mNormalTextAppearance = new ForegroundColorSpan(Color.GRAY);
    mMinLen = minLen;
    mMaxLen = maxLen;
    updateErrorText();
    }

    private void updateErrorText()
    {
    mErrorText.clear();
    mErrorText.clearSpans();
    final int length = mTextInputLayout.getEditText().length();
    if(length > 0){
    mErrorText.append(String.valueOf(length));
    mErrorText.append(" / ");
    mErrorText.append(String.valueOf(mMaxLen));
    mErrorText.setSpan(mAlignmentSpan, 0, mErrorText.length(),
    Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    if(hasValidLength()){
    mErrorText.setSpan(mNormalTextAppearance, 0, mErrorText.length(),
    Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    }
    }
    mTextInputLayout.setError(mErrorText);
    }

    public boolean hasValidLength()
    {
    final int length = mTextInputLayout.getEditText().length();
    return (length >= mMinLen && length <= mMaxLen);
    }

    @Override
    public void afterTextChanged(Editable s)
    {
    updateErrorText();
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after)
    {
    //
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count)
    {
    //
    }
    }
    20 changes: 20 additions & 0 deletions TestActivity
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    import android.os.Bundle;
    import android.support.design.widget.TextInputLayout;
    import android.support.v7.app.AppCompatActivity;


    public class TestActivity extends AppCompatActivity
    {
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);

    TextInputLayout text1 = (TextInputLayout) findViewById(R.id.text1);
    TextInputLayout text2 = (TextInputLayout) findViewById(R.id.text2);

    text1.getEditText().addTextChangedListener(new CharacterCountErrorWatcher(text1, 0, 10));
    text2.getEditText().addTextChangedListener(new CharacterCountErrorWatcher(text2, 5, 10));
    }
    }
    36 changes: 36 additions & 0 deletions activity_test.xml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="24dp"
    >

    <android.support.design.widget.TextInputLayout
    android:id="@+id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >
    <EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Text Hint 1"
    android:singleLine="true"
    />
    </android.support.design.widget.TextInputLayout>
    <android.support.design.widget.TextInputLayout
    android:id="@+id/text2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >
    <EditText
    android:id="@+id/text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Text Hint 2"
    />
    </android.support.design.widget.TextInputLayout>
    </LinearLayout>