How to consistently set EditText Selected Underline Color Programmatically
Asked Answered
P

5

11

I'm trying to build a renderer for Xamarin Forms. The renderer needs to set the EditText underline color to "Active Color" when selected and "Hint Color" when deselected. My initial setup looks something like this.

note: here's the path to the full source file
https://github.com/XamFormsExtended/Xfx.Controls/blob/issue-%236/src/Xfx.Controls.Droid/Renderers/XfxEntryRendererDroid.cs

// called when control is created or when Colors are changed.
protected virtual void SetLabelAndUnderlineColor()
{
    var defaultColor = GetPlaceholderColor();
    var activeColor = GetActivePlaceholderColor();

    SetHintLabelDefaultColor(defaultColor);
    SetHintLabelActiveColor(activeColor);
    SetUnderlineColor(_hasFocus ? activeColor : defaultColor);
}

private void SetUnderlineColor(AColor color)
{
    var bg = ColorStateList.ValueOf(color);
    ViewCompat.SetBackgroundTintList(EditText,bg);
}

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

private void SetHintLabelDefaultColor(AColor color)
{
    var hint = Control.Class.GetDeclaredField("mDefaultTextColor");
    hint.Accessible = true;
    hint.Set(Control, new ColorStateList(new int[][] { new[] { 0 } }, new int[] { color }));
}

Outside of this, I also have an OnClickListener that updates the underline only when the state changes

private void ControlOnFocusChange(object sender, FocusChangeEventArgs args)
{
    _hasFocus = args.HasFocus;
    SetUnderlineColor(args.HasFocus ? GetPlaceholderColor() : GetActivePlaceholderColor());
}

The problem is that when I tap into the EditText, it's hit or miss as to what I'm going to see for an underline color. I can pretty much guarantee that it'll be the default android:colorAccent the very first time. Then after that it switches between the "Hint Color" and the "Placeholder Color".

note: if I change the SetUnderlineColor method to this (below), it no longer uses the "Hint Color" in the mix, but I still get the android:colorAccent color as the initial underline color, after that it behaves as expected.

private void SetUnderlineColor(AColor color)
{
    var bg = EditText.Background;
    DrawableCompat.SetTint(bg,color);
    EditText.SetBackground(bg);
}

What do I need to do to set the INITIAL selected color of the EditText to my chosen activeColor / 'focused color' (purple)?

In this animation I am simply selecting and deselecting the EditText enter image description here

Paradrop answered 7/12, 2017 at 5:45 Comment(4)
What about using the android:theme=="@style/MyEditText" in your EditText tag, and the style can be this:<style name="MyEditText" parent="Theme.AppCompat.Light"> <item name="colorControlNormal">@color/defaultColor</item> <item name="colorControlActivated">@color/activeColor </item> </style>.Ionogen
Thanks @JoeLv but unfortunately there is no XML for me to do this with. This is going to be a re-usable control that gives the consumer access to the colors. The control is written completely in code.Paradrop
You could extend application to set any defaults within the scope of the applicationGriffon
Unfortunately that's not really how Xamarin.Forms works.Paradrop
P
9

So the solution for me was to go pure AppCompat

So I'm adding an AppCompatEditText to the TextInputLayout

protected EditText EditText => Control.EditText;

protected override TextInputLayout CreateNativeControl()
{
    var textInputLayout = new TextInputLayout(Context);
    var editText = new AppCompatEditText(Context)
    {
        SupportBackgroundTintList = ColorStateList.ValueOf(GetPlaceholderColor())
    };
    textInputLayout.AddView(editText);
    return textInputLayout;
}

Then from there I was able to set the underline consistently with this.

private void ControlOnFocusChange(object sender, FocusChangeEventArgs args)
{
    _hasFocus = args.HasFocus;
    SetUnderlineColor(_hasFocus ?  GetActivePlaceholderColor(): GetPlaceholderColor());
} 

private void SetUnderlineColor(AColor color)
{
    var element = (ITintableBackgroundView)EditText;
    element.SupportBackgroundTintList = ColorStateList.ValueOf(color);
}

full source code here.

Paradrop answered 12/12, 2017 at 3:38 Comment(0)
B
2

Modify your code in XfxEntryRendererDroid ControlOnFocusChange method like this :

private void ControlOnFocusChange(object sender, FocusChangeEventArgs args)
{
    _hasFocus = args.HasFocus;
    if (_hasFocus)
    {
        ...   

        EditText.PostDelayed(() =>
            {
                //Add the following code
                SetUnderlineColor(GetActivePlaceholderColor());
                EditText.RequestFocus();
                manager.ShowSoftInput(EditText, 0);
            },
            0);//Change it to 0
    }
    ...
}

Effect.

Bentham answered 12/12, 2017 at 2:53 Comment(0)
S
1

Why don't you change the tint colour at runtime using this (May be in your text changed event):

ViewCompat.SetBackgroundTintList(_YourView , ColorStateList.ValueOf(Color.ParseColor(Resources.GetString(Resource.Color.blueLine))));

Anyways Goodluck!

Stagy answered 7/12, 2017 at 7:29 Comment(1)
that's what I'm doing on the ControlOnFocusChange event handler.Paradrop
D
0

You need to set the backgroundTintList or supportBackgroundTintList on the EditText to an instance of ColorStateList

ColorStateList colorStateList = ColorStateList.valueOf(color)
editText.setSupportBackgroundTintList(colorStateList)

OR

I think that if you want to change a bottom line color, then you can change using this below line

editText.getBackground().mutate().setColorFilter(getResources().getColor(R.color.your_color), PorterDuff.Mode.SRC_ATOP);

And Application theame like this:-

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>

    <item name="colorControlNormal">@color/colorAccent</item>
    <item name="colorControlActivated">@color/colorAccent</item>
    <item name="colorControlHighlight">@color/colorAccent</item>

</style>

Please check this Example

Hope this Link1 Link2 helps you.

Duodenary answered 9/12, 2017 at 5:58 Comment(7)
EditText doesn't have SupportBackgroundTintList because it's not AppCompat. I've already tried using SetBackgroundTintList, but I'm getting the same behavior.Paradrop
@ChaseFlorell Please check example link. i thought it's helpful to you.Duodenary
@ChaseFlorell check updated answer and example link. hope you'll get solutionDuodenary
Thank you for upvote my answer if it's going to help to someone. Hey @ChaseFlorell mark as a right if this answer gave you a help.Duodenary
I am not the upvote, unfortunately this does not solve the issue. The issue is that the very first time focus is given on the entry, the underline color is colorAccent instead of the color I've defined. Every subsequent focus sets the underline color appropriately. I don't know how to get it to be the correct color on the initial focus.Paradrop
So I ended up making it work by switching out my EditText for an AppCompatEditText. Changing that out gave me access to setSupportBackgroundTintList which ended up helping me get to where I needed to go. I posted the full answer and source code.Paradrop
Ok great if your problem was solved then enjoy your day. @ChaseFlorellDuodenary
M
-1

To change color you can use below code

 editText.getBackground().mutate().setColorFilter(your_color), PorterDuff.Mode.SRC_ATOP);

And to set different color underline for EditText view on focus change

    editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                editText.getBackground().mutate().setColorFilter(getResources().getColor(android.R.color.holo_purple), PorterDuff.Mode.SRC_ATOP);
            }else {
                editText.getBackground().mutate().setColorFilter(getResources().getColor(android.R.color.holo_red_dark), PorterDuff.Mode.SRC_ATOP);
            }
        }
    });
Meridethmeridian answered 11/12, 2017 at 6:38 Comment(2)
if you look at the last two code blocks in my question, you'll see that is essentially what I'm doing.Paradrop
You are trying to change background tint color. editText.getBackground().mutate().setColorFilter(your_color), PorterDuff.Mode.SRC_ATOP); will change existing drawable color only to the required color. Please give a try changing by this method. I tested and it is working perfectly fineMeridethmeridian

© 2022 - 2024 — McMap. All rights reserved.