android: Add TextInputLayout child class that displays a helper text below the text...
authorTobias Brunner <tobias@strongswan.org>
Fri, 29 Apr 2016 16:15:29 +0000 (18:15 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 2 May 2016 16:39:17 +0000 (18:39 +0200)
Also hides the error message if the text is changed.

src/frontends/android/app/src/main/java/org/strongswan/android/ui/widget/TextInputLayoutHelper.java [new file with mode: 0644]
src/frontends/android/app/src/main/res/values/attrs.xml

diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/widget/TextInputLayoutHelper.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/widget/TextInputLayoutHelper.java
new file mode 100644 (file)
index 0000000..45b0ae5
--- /dev/null
@@ -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();
+               }
+       }
+}
index 6c3480b..592555c 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012 Tobias Brunner
-    Hochschule fuer Technik Rapperswil
+    Copyright (C) 2012-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
@@ -17,4 +17,7 @@
     <declare-styleable name="Fragment">
         <attr name="read_only" format="boolean" />
     </declare-styleable>
+    <declare-styleable name="TextInputLayoutHelper">
+        <attr name="helper_text" format="string" />
+    </declare-styleable>
 </resources>