Skip to content

Instantly share code, notes, and snippets.

@slightfoot
Last active May 12, 2022 08:11
Show Gist options
  • Save slightfoot/171f5002d06089cae460 to your computer and use it in GitHub Desktop.
Save slightfoot/171f5002d06089cae460 to your computer and use it in GitHub Desktop.
Material Design - Text field input - Over/under character or word count (android.support.design.widget.TextInputLayout) http://www.google.com/design/spec/patterns/errors.html#errors-user-input-errors
<?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>
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 <simon@demondevelopers.com>
*/
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)
{
//
}
}
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));
}
}
@slightfoot
Copy link
Author

Example of a single-line with character counter with user input text Example of a single-line with character counter with error text
Example of a multi-line with character counter with user input text Example of a multi-line with character counter with error text

Copy link

ghost commented Mar 3, 2017

Hi,

I'm trying to implement the same kind of TextInputLayout with an EditText. My purpose is to display the error message to the right just as you have done here. Even with your method, I'm unable to do that. If you have time, could you please respond to this: http://stackoverflow.com/questions/42575825/textinputlayout-error-right-align

@AUbillaOliva
Copy link

Can you post the updated code please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment