2
votes

In our application we have some controls that are Entry controls that take in numbers, so we want the user to be able to type into them. Other controls are popup selections such as a Date, or a Picker control, of which we code as Label controls.

To give the user the same consistency as Entry controls, for iOS we put the same frames around them as an Entry control in iOS such as this:

Standard Entry Control Xaml:

<Entry Grid.Row="0" Grid.Column="1" Keyboard="Numeric" ReturnType="Done" WidthRequest="60" 
        Text="{Binding SocketItem.QuantityPerSys, Converter={StaticResource IntComma}}" 
        TextChanged="OnIntegerEntryChanging" Placeholder="0" 
        AutomationId="SocketQtySysValueEntry" />

Mimic'ed Entry Control for iOS Rendering:

<Frame Grid.Row="1" Grid.Column="1" AutomationId="SocketDecisionDateEntryFrame">
    <Label Text="{Binding SocketItem.DecisionDate, StringFormat='{0:M/d/yy}', Converter={StaticResource LocalTime}}" 
            HorizontalTextAlignment="Center" HorizontalOptions="FillAndExpand" AutomationId="SocketDecisionDateValueEntry"/>
    <Frame.GestureRecognizers>
        <TapGestureRecognizer Tapped="OnSocketDateTapped" CommandParameter="DecisionDate" />
    </Frame.GestureRecognizers>
</Frame>

However in Android the Entry controls have a line underneath them: Android Entry Control

We want to render these label controls the same as the Entry controls so they are consistent: Label and Entry controls

My assumption is that I have to use a custom renderer of which I already have setup, but with just a normal underline of the text (which is of course what I don't want):

    class UnderlinedLabelRenderer : LabelRenderer
    {
        public UnderlinedLabelRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);
            if (Control != null && Control is FormsTextView textView)
            {
                textView.PaintFlags |= PaintFlags.UnderlineText;
            }
        }
    }

I've tried investigating the actual Xamarin.Forms renderer code for the Entry control, but I'm not familiar enough with it or know exactly which class to look at to figure it out (I'll continue that route in the mean time). I am assuming I'll have to somehow add a new box control to the label cell or something.

I've also looked at this question: Xamarin Forms Android EntryCell Underline which is related but the opposite of what I want to do.

I also tried making the controls disabled Entry controls:

<StackLayout Grid.Row="1" Grid.Column="1" HorizontalOptions="End" AutomationId="OppApplicationValueFrame">
    <controls:ReadonlyEntry Text="{Binding Opportunity.Application}" IsEnabled="False"
           AutomationId="OppApplicationValueEntry"/>
    <StackLayout.GestureRecognizers>
        <TapGestureRecognizer Tapped="OnApplicationTapped" />
    </StackLayout.GestureRecognizers>
</StackLayout>

but that yielded light gray text (due to the disabled). I then created a custom renderer to fix the text:

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

    if (Control != null && Control is FormsEditText editText)
    {
        editText.SetTextColor(Android.Graphics.Color.Gray);
        //editText.SetBackgroundColor(Android.Graphics.Color.Gray);
    }
}

but the underline on the control is still light grey (disabled color). I referenced this question on how to remove the underline: Xamarin Forms Android EntryCell Underline. But doing the opposite of setting it to another color makes the entire cell Gray.

How do I change the color of the underline in the CustomRenderer?

Any help would be great or a place to start looking.

1
FYI: I completed this by implementing a custom control, in iOS a Frame wrapping a Label and in Android a StackLayout wrapping a label followed by a box view. - Wade Baird

1 Answers

0
votes

I think the easiest way to achieve your requirement is to use a Entry instead of a Label, disable the edit ability of the entry and add a TapGestureRecognizers there to handle event:

<StackLayout>

    <Entry IsEnabled="False" Text="test" HorizontalTextAlignment="Center" />

    <StackLayout.GestureRecognizers>
        <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" NumberOfTapsRequired="1" />
    </StackLayout.GestureRecognizers>

</StackLayout>

And I don't think you can achieve this by using a custom renderer of Lable, native TextView does not has this feature.

Another way is to create a custom control, like a view contains a label and a view(height =1) with black background color which stay under the label.

Update:

Code in the custom renderer to change the color of underline:

[assembly: ExportRenderer(typeof(myEntry), typeof(MyEntryRenderer))]
namespace App557.Android
{
    class MyEntryRenderer : EntryRenderer
    {
        public MyEntryRenderer(Context context) : base(context)
        {
        }

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

            if (Control != null)
            {
                EditText editText = Control as EditText;
                editText.Enabled = false;

                editText.SetTextColor(global::Android.Graphics.Color.LightGreen);
                editText.Background.SetColorFilter(global::Android.Graphics.Color.LightGreen, PorterDuff.Mode.SrcIn);

                editText.SetSingleLine(true);
                editText.Ellipsize = TruncateAt.End;
            }
        }
    }
}