Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 89864

[Material] TextInputLayout Renderer (Floating Labels)

$
0
0

Just thought I'd throw this out there. If you want floating labels on your Entry (as found here (by JamesMontemagno)), I've thrown together a custom renderer that extends Entry.

note: this requires the AppCompat stuff to be enabled in your Android App.

First you want to create an axml view and drop it in your /Resources/layout directory.

TextInputLayout.axml

<!-- NOTE: MyAppCompatTheme is important - it MUST apply an AppCompat theme of some sort -->
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TextInputLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:id="@+id/textInputLayout"
  android:theme="@style/MyAppCompatTheme">
  <EditText
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:singleLine="true" />
</android.support.design.widget.TextInputLayout>

From there, just drop this renderer into your Droid Renderers directory (wherever that lives).

MaterialEntryRenderer_Droid.cs

using System.ComponentModel;
using Android.Support.Design.Widget;
using Android.Text;
using Android.Views;
using MyApp.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using TextChangedEventArgs = Android.Text.TextChangedEventArgs;
using View = Android.Views.View;

[assembly: ExportRenderer(typeof (Entry), typeof (MaterialEntryRenderer_Droid))]

namespace MyApp.Droid.Renderers
{
    public class MaterialEntryRenderer_Droid : Xamarin.Forms.Platform.Android.AppCompat.ViewRenderer<Entry, View>
    {
        private TextInputLayout _nativeView;

        private TextInputLayout NativeView
        {
            get { return _nativeView ?? (_nativeView = InitializeNativeView()); }
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement == null)
            {
                var ctrl = CreateNativeControl();
                SetNativeControl(ctrl);

                SetText();
                SetHintText();
                SetBackgroundColor();
                SetTextColor();
                SetIsPassword();
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == Entry.PlaceholderProperty.PropertyName)
            {
                SetHintText();
            }

            if (e.PropertyName == Entry.TextColorProperty.PropertyName)
            {
                SetTextColor();
            }

            if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
            {
                SetBackgroundColor();
            }

            if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
            {
                SetIsPassword();
            }

            if (e.PropertyName == Entry.TextProperty.PropertyName)
            {
                SetText();
            }
        }

        private void EditTextOnTextChanged(object sender, TextChangedEventArgs textChangedEventArgs)
        {
            Element.Text = textChangedEventArgs.Text.ToString();
            NativeView.EditText.SetSelection(Element.Text.Length);
        }

        private void SetText()
        {
            NativeView.EditText.Text = Element.Text;
        }

        private void SetIsPassword()
        {
            NativeView.EditText.InputType = Element.IsPassword
                ? InputTypes.TextVariationPassword | InputTypes.ClassText
                : NativeView.EditText.InputType;
        }

        public void SetBackgroundColor()
        {
            NativeView.SetBackgroundColor(Element.BackgroundColor.ToAndroid());
        }

        private void SetHintText()
        {
            NativeView.Hint = Element.Placeholder;
        }

        private void SetTextColor()
        {
            if (Element.TextColor == Color.Default)
            {
                NativeView.EditText.SetTextColor(NativeView.EditText.TextColors);
            }
            else
            {
                NativeView.EditText.SetTextColor(Element.TextColor.ToAndroid());
            }
        }

        private TextInputLayout InitializeNativeView()
        {
            var view = FindViewById<TextInputLayout>(Resource.Id.textInputLayout);
            view.EditText.TextChanged += EditTextOnTextChanged;
            return view;
        }

        protected override View CreateNativeControl()
        {
            return LayoutInflater.From(Context).Inflate(Resource.Layout.TextInputLayout, null);
        }
    }
}

image

Disclaimer: I am not responsible for your issues ;) - if you have questions or enhancements, post them below.

This renderer currently only supports the following properties.

  • TextColor
  • Placeholder
  • IsPassword
  • BackgroundColor

feel free to add more :)

also, I didn't actually test binding... I did read somewhere that OnElementPropertyChanged doesn't fire on a ViewRenderer if you don't explicitly add the event hooks... that could have been a bug, I don't know. I just statically set these properties (for now).


Viewing all articles
Browse latest Browse all 89864

Trending Articles