android: Add TextInputLayout child class that displays a helper text below the text field

Also hides the error message if the text is changed.
This commit is contained in:
Tobias Brunner 2016-04-29 18:15:29 +02:00
parent 5ffd79b39b
commit 79ba4b285f
2 changed files with 185 additions and 2 deletions

View File

@ -0,0 +1,180 @@
/*
* Copyright (C) 2016 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.strongswan.android.R;
/**
* Layout that extends {@link android.support.design.widget.TextInputLayout} with a helper text
* displayed below the text field when it receives the focus. Also, any error message shown with
* {@link #setError(CharSequence)} is hidden when the text field is changed (this mirrors the
* behavior of {@link android.widget.EditText}).
*/
public class TextInputLayoutHelper extends TextInputLayout
{
private LinearLayout mHelperContainer;
private TextView mHelperText;
public TextInputLayoutHelper(Context context)
{
this(context, null);
}
public TextInputLayoutHelper(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public TextInputLayoutHelper(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextInputLayoutHelper);
String helper = a.getString(R.styleable.TextInputLayoutHelper_helper_text);
a.recycle();
if (helper != null)
{
mHelperContainer = new LinearLayout(context);
mHelperContainer.setOrientation(LinearLayout.HORIZONTAL);
mHelperContainer.setVisibility(View.INVISIBLE);
addView(mHelperContainer, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
mHelperText = new TextView(context);
mHelperText.setText(helper);
mHelperText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.textColorSecondary});
mHelperText.setTextColor(a.getColor(0, mHelperText.getCurrentTextColor()));
a.recycle();
mHelperContainer.addView(mHelperText, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params)
{
super.addView(child, index, params);
if (child instanceof EditText)
{
EditText text = (EditText)child;
text.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 (getError() != null)
{
setError(null);
}
}
});
if (mHelperContainer != null)
{
text.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus)
{
showHelper(hasFocus);
}
});
ViewCompat.setPaddingRelative(mHelperContainer, ViewCompat.getPaddingStart(text),
0, ViewCompat.getPaddingEnd(text), text.getPaddingBottom());
}
}
}
@Override
public void setError(@Nullable CharSequence error)
{
super.setError(error);
if (mHelperContainer != null)
{
if (error == null)
{ /* this frees up space used by the now invisible error message */
setErrorEnabled(false);
}
else
{ /* re-add the helper as the error message should be displayed directly under the textbox */
removeView(mHelperContainer);
addView(mHelperContainer, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
}
}
/**
* Set the helper text to be displayed below the text field.
*
* @attr ref R.styleable#TextInputLayoutHelper_helper_text
*/
public void setHelperText(CharSequence text)
{
mHelperText.setText(text);
}
private void showHelper(boolean show)
{
if (show == (mHelperContainer.getVisibility() == View.VISIBLE))
{
return;
}
if (show)
{
ViewCompat.animate(mHelperContainer)
.alpha(1f)
.setDuration(200)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
@Override
public void onAnimationStart(View view)
{
view.setVisibility(View.VISIBLE);
}
}).start();
}
else
{
ViewCompat.animate(mHelperContainer)
.alpha(0f)
.setDuration(200)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
@Override
public void onAnimationEnd(View view)
{
view.setVisibility(View.INVISIBLE);
}
}).start();
}
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2016 Tobias Brunner
Hochschule fuer Technik Rapperswil HSR Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the under the terms of the GNU General Public License as published by the
@ -17,4 +17,7 @@
<declare-styleable name="Fragment"> <declare-styleable name="Fragment">
<attr name="read_only" format="boolean" /> <attr name="read_only" format="boolean" />
</declare-styleable> </declare-styleable>
<declare-styleable name="TextInputLayoutHelper">
<attr name="helper_text" format="string" />
</declare-styleable>
</resources> </resources>