android: Add TextInputLayout child class that displays a helper text below the text...
[strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / ui / widget / TextInputLayoutHelper.java
1 /*
2 * Copyright (C) 2016 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 package org.strongswan.android.ui.widget;
17
18 import android.content.Context;
19 import android.content.res.TypedArray;
20 import android.support.annotation.Nullable;
21 import android.support.design.widget.TextInputLayout;
22 import android.support.v4.view.ViewCompat;
23 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
24 import android.text.Editable;
25 import android.text.TextWatcher;
26 import android.util.AttributeSet;
27 import android.util.TypedValue;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.widget.EditText;
31 import android.widget.LinearLayout;
32 import android.widget.TextView;
33
34 import org.strongswan.android.R;
35
36 /**
37 * Layout that extends {@link android.support.design.widget.TextInputLayout} with a helper text
38 * displayed below the text field when it receives the focus. Also, any error message shown with
39 * {@link #setError(CharSequence)} is hidden when the text field is changed (this mirrors the
40 * behavior of {@link android.widget.EditText}).
41 */
42 public class TextInputLayoutHelper extends TextInputLayout
43 {
44 private LinearLayout mHelperContainer;
45 private TextView mHelperText;
46
47 public TextInputLayoutHelper(Context context)
48 {
49 this(context, null);
50 }
51
52 public TextInputLayoutHelper(Context context, AttributeSet attrs)
53 {
54 this(context, attrs, 0);
55 }
56
57 public TextInputLayoutHelper(Context context, AttributeSet attrs, int defStyleAttr)
58 {
59 super(context, attrs);
60 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextInputLayoutHelper);
61 String helper = a.getString(R.styleable.TextInputLayoutHelper_helper_text);
62 a.recycle();
63 if (helper != null)
64 {
65 mHelperContainer = new LinearLayout(context);
66 mHelperContainer.setOrientation(LinearLayout.HORIZONTAL);
67 mHelperContainer.setVisibility(View.INVISIBLE);
68 addView(mHelperContainer, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
69
70 mHelperText = new TextView(context);
71 mHelperText.setText(helper);
72 mHelperText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
73 a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.textColorSecondary});
74 mHelperText.setTextColor(a.getColor(0, mHelperText.getCurrentTextColor()));
75 a.recycle();
76
77 mHelperContainer.addView(mHelperText, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
78 }
79 }
80
81 @Override
82 public void addView(View child, int index, ViewGroup.LayoutParams params)
83 {
84 super.addView(child, index, params);
85 if (child instanceof EditText)
86 {
87 EditText text = (EditText)child;
88 text.addTextChangedListener(new TextWatcher() {
89 @Override
90 public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
91
92 @Override
93 public void onTextChanged(CharSequence s, int start, int before, int count) {}
94
95 @Override
96 public void afterTextChanged(Editable s)
97 {
98 if (getError() != null)
99 {
100 setError(null);
101 }
102 }
103 });
104 if (mHelperContainer != null)
105 {
106 text.setOnFocusChangeListener(new OnFocusChangeListener() {
107 @Override
108 public void onFocusChange(View v, boolean hasFocus)
109 {
110 showHelper(hasFocus);
111 }
112 });
113 ViewCompat.setPaddingRelative(mHelperContainer, ViewCompat.getPaddingStart(text),
114 0, ViewCompat.getPaddingEnd(text), text.getPaddingBottom());
115 }
116 }
117 }
118
119 @Override
120 public void setError(@Nullable CharSequence error)
121 {
122 super.setError(error);
123 if (mHelperContainer != null)
124 {
125 if (error == null)
126 { /* this frees up space used by the now invisible error message */
127 setErrorEnabled(false);
128 }
129 else
130 { /* re-add the helper as the error message should be displayed directly under the textbox */
131 removeView(mHelperContainer);
132 addView(mHelperContainer, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
133 }
134 }
135 }
136
137 /**
138 * Set the helper text to be displayed below the text field.
139 *
140 * @attr ref R.styleable#TextInputLayoutHelper_helper_text
141 */
142 public void setHelperText(CharSequence text)
143 {
144 mHelperText.setText(text);
145 }
146
147 private void showHelper(boolean show)
148 {
149 if (show == (mHelperContainer.getVisibility() == View.VISIBLE))
150 {
151 return;
152 }
153 if (show)
154 {
155 ViewCompat.animate(mHelperContainer)
156 .alpha(1f)
157 .setDuration(200)
158 .setListener(new ViewPropertyAnimatorListenerAdapter() {
159 @Override
160 public void onAnimationStart(View view)
161 {
162 view.setVisibility(View.VISIBLE);
163 }
164 }).start();
165 }
166 else
167 {
168 ViewCompat.animate(mHelperContainer)
169 .alpha(0f)
170 .setDuration(200)
171 .setListener(new ViewPropertyAnimatorListenerAdapter() {
172 @Override
173 public void onAnimationEnd(View view)
174 {
175 view.setVisibility(View.INVISIBLE);
176 }
177 }).start();
178 }
179 }
180 }