dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.04k stars 1.73k forks source link

Convert Android Material Button over to using our shadow implementation #2918

Open PureWeen opened 2 years ago

PureWeen commented 2 years ago

Description

Currently the behavior on the Android Material Button implements shadows via elevation and translationZ changes. The native button has a default elevation and then when the button is "pressed" the translationZ is changed.

This means that users can't reliably modify the shadow of the native button using our Shadow APIs. This also can cause unexpected behavior when trying to place content over the button (https://github.com/xamarin/Xamarin.Forms/issues/7300)

We should look at zeroing out the elevation, removing the translationZ state change, and just replicating the shadow press change behavior using our shadow APIs. Currently if users try to use Shadow with Button it will most likely cause visual conflicts between native/xplat behavior.

ivan-todorov-progress commented 2 years ago

We are tracking this issue as well. Please, consider this more like a bug, than a mere enhancement. Currently, we are avoiding the built-in button and are using our own custom implementation for this reason. The default material button might look OK in some cases on Android, but most of the time it looks too ugly to put in a real app: buttons buttons_pressed

jsuarezruiz commented 2 years ago

@Redth @PureWeen Could we consider this a bug more than a enhancement?

ivan-todorov-progress commented 2 years ago

In case someone is curious what is my workaround, here is a "quick and dirty" fix:

internal class MyButton : Button
{
    protected override void OnHandlerChanged()
    {
        base.OnHandlerChanged();

#if ANDROID
        var nativeView = (Android.Views.View)this.Handler.NativeView;

        nativeView.StateListAnimator = null;
#endif
    }
}
ghost commented 2 years ago

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.

AdamDiament commented 1 year ago

In case someone is curious what is my workaround, here is a "quick and dirty" fix:

internal class MyButton : Button
{
    protected override void OnHandlerChanged()
    {
        base.OnHandlerChanged();

#if ANDROID
        var nativeView = (Android.Views.View)this.Handler.NativeView;

        nativeView.StateListAnimator = null;
#endif
    }
}

FYI @jfversluis this is still an issue in July 2023, the workaround works but NativeView is now PlatformView in net7.0-android

so,

internal class WellBehavedButton : Button
{
    protected override void OnHandlerChanged()
    {
        base.OnHandlerChanged();

#if ANDROID
        var nativeView = (Android.Views.View)this.Handler?.PlatformView;

        if (nativeView is not null)
        {
            nativeView.StateListAnimator = null;
        }

#endif
    }
}

Is there a less dirty way to do this without losing some button tapped functionality? (https://github.com/dotnet/maui/issues/5347#issuecomment-1070259683)

AdamDiament commented 1 year ago

Here is a workaround approach using a handler so we can continue to use regular <Button /> elements in our xaml at least:


    public class NoShadowAndroidButtonHandler : ButtonHandler
    {
        public NoShadowAndroidButtonHandler()
        {
            Mapper.AppendToMapping("RemoveShadowCustomisation", (handler, _) =>
            {
                handler.PlatformView.StateListAnimator = null;
            });
        }

    }

Then in MauiProgram configure handlers:

#if ANDROID
        handlers.AddHandler(typeof(Button), typeof(NoShadowAndroidButtonHandler));
#endif