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));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment