Search code examples
c#androidxamarin.formseditor

Xamarin Forms and Material design, how to change hint color


I tried to create a Material Design Entry for Xamarin Forms and I have a problem with the hint color and the bottom line.

EDIT with York Shen answer:

Xaml Page

<customControls:CustomEntry
    Keyboard="Email"
    Placeholder="EMAIL"
    Style="{StaticResource EntryAccount}"
    Text="{Binding Email}" />

EntryAccount Style

<Style x:Key="EntryAccount" TargetType="customControls:CustomEntry">
    <Setter Property="PlaceholderColor" Value="{StaticResource BackgroundColor}" />
    <Setter Property="BottomLineColor" Value="{StaticResource BackgroundColor}" />
    <Setter Property="TextColor" Value="{StaticResource BackgroundColor}" />
    <Setter Property="FontSize" Value="{StaticResource Subtitle1}" />
    <Setter Property="FontFamily" Value="{StaticResource Subtitle1Font}" />
</Style>

CustomEntry

public class CustomEntry : Entry
{
    public static readonly BindableProperty BottomLineColorProperty =
        BindableProperty.Create(nameof(BottomLineColor), typeof(Color), typeof(CustomEntry), Color.Blue);

    public Color BottomLineColor
    {
        get => (Color) GetValue(BottomLineColorProperty);
        set => SetValue(BottomLineColorProperty, value);
    }
}

CustomEntryRenderer

public class CustomEntryRenderer : Xamarin.Forms.Platform.Android.AppCompat.ViewRenderer<CustomEntry, TextInputLayout>
{
    public CustomEntryRenderer(Context context) : base(context)
    {
    }

    protected EditText EditText => Control.EditText;

    protected override TextInputLayout CreateNativeControl()
    {
        var textInputLayout = new TextInputLayout(Context);
        var editText = new AppCompatEditText(Context);
        editText.SetTextSize(ComplexUnitType.Sp, (float) Element.FontSize);
        textInputLayout.AddView(editText);
        return textInputLayout;
    }

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

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

            var activeColor = Element.BottomLineColor.ToAndroid(global::Android.Resource.Attribute.ColorAccent, Context);

            var hintText = Control.Class.GetDeclaredField("mFocusedTextColor");
            hintText.Accessible = true;
            hintText.Set(Control, new ColorStateList(new int[][] {new[] {0}}, new int[] {activeColor}));

            EditText.Enabled = Element.IsEnabled;
            Control.Hint = Element.Placeholder;
            EditText.SetTextColor(Element.TextColor.ToAndroid());
        }
    }
}

Element.TextColor & activeColor correctly get the colors that I pass in param.

But this is my results:

1

2


Solution

  • Xamarin Forms and Material design, how to change hint color

    You could add an AppCompatEditText to the TextInputLayout:

    protected EditText EditText => Control.EditText;
    
    protected override TextInputLayout CreateNativeControl()
    {
        var textInputLayout = new TextInputLayout(Context);
        var editText = new AppCompatEditText(Context);
        editText.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
        textInputLayout.AddView(editText);
        return textInputLayout;
    }
    

    Then set hint text color like this:

    var activeColor = Element.ActiveHintTextColor.ToAndroid(global::Android.Resource.Attribute.ColorAccent, Context);
    var hintText = Control.Class.GetDeclaredField("mFocusedTextColor");
    hintText.Accessible = true;
    hintText.Set(Control, new ColorStateList(new int[][] { new[] { 0 } }, new int[] { activeColor }));
    

    Source code

    CustomEntry:

    public class CustomEntry : Entry
    {
        public static readonly BindableProperty ActiveHintTextColorProperty = BindableProperty.Create(nameof(ActiveHintTextColor),
           typeof(Color),
           typeof(CustomEntry),
           Color.Accent);
    
        /// <summary>
        /// ActiveHintTextColor summary. This is a bindable property.
        /// </summary>
        public Color ActiveHintTextColor
        {
            get { return (Color)GetValue(ActiveHintTextColorProperty); }
            set { SetValue(ActiveHintTextColorProperty, value); }
        }
    }
    

    Renderer:

    public class CustomEntryRenderer : Xamarin.Forms.Platform.Android.AppCompat.ViewRenderer<CustomEntry, TextInputLayout>
    {
        public CustomEntryRenderer (Context context) : base(context)
        {
        }
    
        protected EditText EditText => Control.EditText;
    
        protected override TextInputLayout CreateNativeControl()
        {
            var textInputLayout = new TextInputLayout(Context);
            var editText = new AppCompatEditText(Context);
            editText.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
            textInputLayout.AddView(editText);
            return textInputLayout;
        }
    
        protected override void OnElementChanged(ElementChangedEventArgs<XfxEntry> e)
        {
            base.OnElementChanged(e);
    
            if (e.NewElement != null)
            {
                var ctrl = CreateNativeControl();
                SetNativeControl(ctrl);
    
                var activeColor = Element.ActiveHintTextColor.ToAndroid(global::Android.Resource.Attribute.ColorAccent, Context);
    
                var hintText = Control.Class.GetDeclaredField("mFocusedTextColor");
                hintText.Accessible = true;
                hintText.Set(Control, new ColorStateList(new int[][] { new[] { 0 } }, new int[] { activeColor }));
    
                EditText.Enabled = Element.IsEnabled;
                Control.Hint = Element.Placeholder;
                EditText.SetTextColor(Element.TextColor.ToAndroid());
            }
        }
    }
    

    Usage:

    <local:CustomEntry
        Placeholder="Enter your name:"
        Text="Name"
        ActiveHintTextColor="Blue"
        PlaceholderColor="Black"
            />
    

    Effect

    Update:

    Set the bottom line color:

    var element = (ITintableBackgroundView)EditText;
    //using AColor = Android.Graphics.Color;
    element.SupportBackgroundTintList = ColorStateList.ValueOf(AColor.White);