maui icon indicating copy to clipboard operation
maui copied to clipboard

Entry and Editor: option to disable borders and underline (focus)

Open leoderja opened this issue 2 years ago • 29 comments

Description

Would be very usefull a property called HideBorder of boolean type. The same for the underline that appears bellow the control when it has the focus.

Public API Changes

<Entry HideBorder="true" HideUnderLine="true" />

Intended Use-Case

This change is useful when you need to design a cleaner UI.

leoderja avatar Jun 09 '22 18:06 leoderja

Instead of these two boolean properties I would prefer BorderThickness (set to 0 to hide the borders) and UnderlineColor + UnderlineFocusedColor (set to transparent to hide it). This supports much more scenarios and aligns better with other control properties.

Symbai avatar Jun 09 '22 23:06 Symbai

it doesn't necessarily have to be "instead of"... one thing doesn't invalidate the other

leoderja avatar Jun 10 '22 18:06 leoderja

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Aug 12 '22 12:08 ghost

This is really easy to do using handlers:

In CreateMauiApp add this:

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { // Remove underline: h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); });

Then just subclass Entry control and add the NoUnderline property and in XAML set it to True.

philipag avatar Oct 02 '22 19:10 philipag

This is really easy to do using handlers:

In CreateMauiApp add this:

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { // Remove underline: h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); });

Then just subclass Entry control and add the NoUnderline property and in XAML set it to True.

Tried, works, thank you! Instead of placing it in MauiProgram/CreateMauiApp() I placed it in Platforms/Android/MainApplication/CreateMauiApp: `namespace MyNamespace { [Application] public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { }

    protected override MauiApp CreateMauiApp()
    {
        // Remove Entry control underline
        Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) =>
        {
            h.PlatformView.BackgroundTintList =
                Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
        });

        return MauiProgram.CreateMauiApp();
    }
}

}` It is for Android only, would be nice to see the magic line for iOS as well.

balintn22 avatar Dec 30 '22 22:12 balintn22

Any update for iOS to remove underline ?

GnanaPriyaNamasivayam avatar Jan 11 '23 11:01 GnanaPriyaNamasivayam

Here is iOS workaround.

    public class BorderlessEntry : Entry
    {
        public BorderlessEntry() 
        {
        }       
    }

    public App()
    {
        InitializeComponent();

        SetupHandlers();

        MainPage = new AppShell();
    }
    private void SetupHandlers()
    {
        Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
        {
            if (view is BorderlessEntry)
            {

#if IOS || MACCATALYST
                handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None;
#endif
            }
        });
    }

kosalawije avatar Jan 17 '23 07:01 kosalawije

For Android, it accepts the enum with namespace but for iOS, it does not. The app fails to compile. image

Do you know the reason for this?

It's strange that android specific code only works inside device info platform and as common but not working when added inside compile directive so I'm trying to use the DeviceInfo platform instead.

GnanaPriyaNamasivayam avatar Jan 17 '23 08:01 GnanaPriyaNamasivayam

Это очень легко сделать с помощью обработчиков: В CreateMauiApp добавьте это: Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { // Remove underline: h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); }); Затем просто создайте подкласс элемента управления Entry и добавьте свойство NoUnderline, а в XAML установите для него значение True.

Попробовал, работает, спасибо! Вместо того, чтобы поместить его в MauiProgram/CreateMauiApp(), я поместил его в Platforms/Android/MainApplication/CreateMauiApp: `namespace MyNamespace { [Application] public class MainApplication: MauiApplication { public MainApplication (дескриптор IntPtr, владение JniHandleOwnership) : base (дескриптор, владение ) { }

    protected override MauiApp CreateMauiApp()
    {
        // Remove Entry control underline
        Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) =>
        {
            h.PlatformView.BackgroundTintList =
                Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
        });

        return MauiProgram.CreateMauiApp();
    }
}

}` Это только для Android, было бы неплохо увидеть волшебную строку и для iOS.

I also used this method, but I have a text in the border, which cuts it off from above, how is it possible to indent the text so that it is centered on the border?

K0Ma19 avatar Mar 27 '23 08:03 K0Ma19

This would be a nice implementation. It's worth noting that the workaround in the thread doesn't seem to work on some newer versions of Android.

I wanted this behavior disabled globally (I mean it is a BorderlessEntry control), so I just set that style in the ConnectHandler:

namespace Project.Droid.Handlers
{
    public class BorderlessEntryHandler : EntryHandler
    {
        protected override void ConnectHandler( AppCompatEditText platformView )
        {
            base.ConnectHandler( platformView );

            platformView.Background = null;
            platformView.SetPadding( 0, 0, 0, 0 );

            // We do this to hide the bottom underline in MAUI.
            platformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf( Colors.Transparent.ToAndroid() );
        }
    }
}

& of course register my handler in the MauiProgram:

#if ANDROID
    handlers.AddHandler( typeof( BorderlessEntry ), typeof( Droid.Handlers.BorderlessEntryHandler ) );
#endif

bradencohen avatar Apr 28 '23 17:04 bradencohen

使用处理程序真的很容易做到:

在CreateMauiApp中添加以下内容:

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { // Remove underline: h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); });

然后,只需子类 Entry 控件并添加 NoUnderline 属性,并在 XAML 中将其设置为 True。

What if I only want to change a certain entry separately? Your method is globally effective. @hartez

nnn149 avatar Jun 06 '23 03:06 nnn149

@nnn149 You can make this conditional on a custom property which you can then e.g. set in XAML:

internal class OurEntry : Entry
{
public bool NoUnderline { get; set; }
}

and then

		Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(OurEntry.NoUnderline), (h, v) =>
		{
			// Remove underline:
			var oe = v as OurEntry;
			if (oe != null && oe.NoUnderline)
				h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
		});

philipag avatar Jun 06 '23 03:06 philipag

@nnn149 You can make this conditional on a custom property which you can then e.g. set in XAML:

internal class OurEntry : Entry
{
public bool NoUnderline { get; set; }
}

and then

		Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(OurEntry.NoUnderline), (h, v) =>
		{
			// Remove underline:
			var oe = v as OurEntry;
			if (oe != null && oe.NoUnderline)
				h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
		});

Thank you, it works!

nnn149 avatar Jun 06 '23 04:06 nnn149

Where's the windows solutions... is Maui going to be like Xamarin where it's only iOS and Android...

BobbyCannon avatar Jun 07 '23 00:06 BobbyCannon

would be nice to see for windows, but also i do not want blue underline to appear when entry is focused on windows

Tamirlan7 avatar Jun 19 '23 05:06 Tamirlan7

this is how i removed entry's borders for windows

public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .UseMauiCommunityToolkit()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });

#if WINDOWS
            Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderlineWindows", (h, v) =>
            {
                h.PlatformView.BorderThickness = new Microsoft.UI.Xaml.Thickness()
                {
                    Bottom = 0,
                    Top = 0,
                    Left = 0,
                    Right = 0,
                };
            });
#endif

Tamirlan7 avatar Jun 19 '23 05:06 Tamirlan7

This is really easy to do using handlers: In CreateMauiApp add this: Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { // Remove underline: h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); }); Then just subclass Entry control and add the NoUnderline property and in XAML set it to True.

Tried, works, thank you! Instead of placing it in MauiProgram/CreateMauiApp() I placed it in Platforms/Android/MainApplication/CreateMauiApp: `namespace MyNamespace { [Application] public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { }

    protected override MauiApp CreateMauiApp()
    {
        // Remove Entry control underline
        Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) =>
        {
            h.PlatformView.BackgroundTintList =
                Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
        });

        return MauiProgram.CreateMauiApp();
    }
}

}` It is for Android only, would be nice to see the magic line for iOS as well.

Thanks! This works great. Is there a way to change the colour of the caret?

Dan-Banfield avatar Jul 02 '23 19:07 Dan-Banfield

Those changes are enough to remove all visual effects from the entry:

gradientDrawable.SetColor(global::Android.Graphics.Color.Transparent);
nativeView.SetBackground(gradientDrawable);

I did it for all platforms, you can take a look at it: https://github.com/enisn/Xamarin.Forms.Plainer/blob/7015e41fb1d681b8f044f027a70e0d4b70a96f77/src/Plainer.Maui/Handlers/EntryViewHandler.cs#L36-L40

enisn avatar Aug 02 '23 10:08 enisn

Is there a way to just change colors of the underline?

OudomMunint avatar Aug 10 '23 06:08 OudomMunint

Those changes are enough to remove all visual effects from the entry:

gradientDrawable.SetColor(global::Android.Graphics.Color.Transparent);
nativeView.SetBackground(gradientDrawable);

I did it for all platforms, you can take a look at it: https://github.com/enisn/Xamarin.Forms.Plainer/blob/7015e41fb1d681b8f044f027a70e0d4b70a96f77/src/Plainer.Maui/Handlers/EntryViewHandler.cs#L36-L40

Net 8 Preview 7, additionally requires: nativeView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());

nelsonrc avatar Sep 10 '23 07:09 nelsonrc

This is really easy to do using handlers:

In CreateMauiApp add this:

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { // Remove underline: h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); });

Then just subclass Entry control and add the NoUnderline property and in XAML set it to True.

In my case I don't subclass Entry, Just add handler in MauiProgram and work for every Entry in my xlml pages

mfranc28 avatar Oct 04 '23 08:10 mfranc28

Using .net 8 (8.0.0-rc.2.9373/8.0.100-rc.2), what am I doing wrong? I'm trying to get rid of the Entry underline in Android, and adding

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { #if ANDROID h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); #endif });

to MauiProgram.cs will make the entire entry transparent. Adding BackgroundColor in styles.xaml or setting it on the Entry in my .xaml file doesn't change the color. So right now I can choose from ugly underline, or no BackgroundColor?

Is the goto really to create my own entry, referencing different handlers that sets the "BackgrundTintList" to my desired BackgroundColor?

mla03 avatar Oct 16 '23 12:10 mla03

Using .net 8 (8.0.0-rc.2.9373/8.0.100-rc.2), what am I doing wrong? I'm trying to get rid of the Entry underline in Android, and adding

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderline", (h, v) => { #if ANDROID h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); #endif });

to MauiProgram.cs will make the entire entry transparent. Adding BackgroundColor in styles.xaml or setting it on the Entry in my .xaml file doesn't change the color. So right now I can choose from ugly underline, or no BackgroundColor?

Is the goto really to create my own entry, referencing different handlers that sets the "BackgrundTintList" to my desired BackgroundColor?

I ran into this too (setting the BackgroundTintList hides any MAUI BackgroundColor), and was able to work around it like this:


// Either transparent or the provided background color
var backgroundTint = editor.BackgroundColor.IsDefault() ? Android.Content.Res.ColorStateList.ValueOf( Colors.Transparent.ToAndroid() )
: Android.Content.Res.ColorStateList.ValueOf( editor.BackgroundColor.ToAndroid() );

handler.PlatformView.BackgroundTintList = backgroundTint;

bradencohen avatar Nov 03 '23 20:11 bradencohen

this is how i removed entry's borders for windows

public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .UseMauiCommunityToolkit()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });

#if WINDOWS
            Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderlineWindows", (h, v) =>
            {
                h.PlatformView.BorderThickness = new Microsoft.UI.Xaml.Thickness()
                {
                    Bottom = 0,
                    Top = 0,
                    Left = 0,
                    Right = 0,
                };
            });
#endif

I don't think this works when the Entry is highlighted. At least I dod something similar (but not 100% the same, using a Handler) and I couldn't get this approach to work properly when entry got focused (border would appear).

However, the following seems to work fine on Windows when using handlers - this would be the native Windows implementation of a custom view:

using MauiEntry = Microsoft.Maui.Controls.Entry;

public class NativeTextField : Grid, IDisposable
{
    private readonly TextField _textField;

    private readonly TextBox _textBox;

    // keep a reference, so we can unhook event on Dispose
    private MauiEntry _entry;

    // TextField is my virtual view, a custom class that behaves a bit like an entry
    public NativeTextField(TextField textField) 
    {
        _textField = textField;

        _entry = new MauiEntry();
        _entry.Focused += Entry_Focused;
        _textBox = (TextBox)_entry.ToPlatform(textField.Handler!.MauiContext!);          
    }

    public void Dispose()
    {
        _entry.Focused -= Entry_Focused;
        
        GC.SuppressFinalize(this);
    }
    
    // when focused: recursively look for a child border and if found, hide it
    private void Entry_Focused(object? sender, Microsoft.Maui.Controls.FocusEventArgs e)
    {
        if (_textBox.GetFirstChildOfType<Border>() is Border border)
        {
            border.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
        }
    }
}

// instead of this manual implementation, could also use a CommunityToolkit WinUI Nuget package that has some Linq stuff
internal static class DependencyObjectExtensions
{
    internal static DependencyObject? GetFirstChildOfType<T>(this DependencyObject textBox) where T : DependencyObject
    {
        var childCount = VisualTreeHelper.GetChildrenCount(textBox);

        for (var i = 0; i < childCount; i++)
        {
            var child = VisualTreeHelper.GetChild(textBox, i);
            if (child.GetType().Equals(typeof(T)))
            {
                return child;
            }
            else
            {
                if (GetFirstChildOfType<T>(child) is T obj)
                {
                    return obj;
                }
            }
        }

        return null;
    }  
}

P.S.: I think more or less the same code could be used in a Behavior, which would probably be a better idea than writing a custom Entry.

wolfgang-ironsoftware avatar Dec 25 '23 02:12 wolfgang-ironsoftware

That works nicely to remove that bottom border of the Entry control but its not removing the border of the text when I type something in the Entry. Is there a quick hack to remove that as well?

I've tried changing the BackgroundColor as well as setting the Background to null as suggested in many links but that did not do the trick for the underline of the text when typing in the Entry.

For context, my issue is on android, by adding h.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); I can perfectly fine remove the bottom border but as you can see here, when typing something, I still get a different underline which I would like to remove as well.

qemu-system-x86_64_2024-01-23_15-00-34

Best regards.

nucombo avatar Jan 23 '24 17:01 nucombo

Have you made any further progress on this issue?

HuaFangYun avatar Mar 21 '24 14:03 HuaFangYun

It would be very useful to have BorderColor and BorderWisth properties on any control. I would like to set these properties similarly as the BackgroundColor.

There is clearly a need for these properties.

It should not be necessary that every developer has to add similar code on platform level to get this done. This should be part of MAUI.

I am looking forward to these properties in the next version :-)

Thanks

eschimmel avatar Mar 26 '24 09:03 eschimmel

This is the solutiont to just change the color!!! I spent so long looking for it :') Go to -> Platforms/Android/Resources/values/colors.xml

Is there a way to just change colors of the underline?

Dorna-10 avatar Mar 28 '24 18:03 Dorna-10

This is such a ubiquitous requirement, this absolutely be in .NET MAUI. Yep easy enough to do with handlers but there have been a couple of regressions, so making this part of .NET MAUI itself would ensure these get picked up in testing of releases. This is absolutely something nearly everyone needs and would be awesome to include.

matt-goldman avatar May 11 '24 03:05 matt-goldman

this is how i removed entry's borders for windows

public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .UseMauiCommunityToolkit()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });

#if WINDOWS
            Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoUnderlineWindows", (h, v) =>
            {
                h.PlatformView.BorderThickness = new Microsoft.UI.Xaml.Thickness()
                {
                    Bottom = 0,
                    Top = 0,
                    Left = 0,
                    Right = 0,
                };
            });
#endif

I was able to remove the borders, in Windows, when Entry is with focus with this line: nativeView.Style = null; No need to add color resources in Platform\Windows\App.xaml too.

rodolfo-sousa avatar Aug 13 '24 17:08 rodolfo-sousa