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
21.97k stars 1.71k forks source link

Fix (or don't) the behavior of calling "Focus" on Android to open the picker #8946

Open PureWeen opened 2 years ago

PureWeen commented 2 years ago

Currently the behavior of calling "Focus" to open the picker dialogs is broken on Android because of this PR. That behavior has always been a bit of a hack and should most likely be replaced by this. That being said it does complicate the migration story to remove this behavior.

We could tie a focus call at the controls level into the APIs we add for https://github.com/dotnet/maui/issues/8945.

Reproduction

<DatePicker Visible="false" x:name="picker" />
picker.Focus()
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.

RemkoVermaeren commented 1 year ago

Did you find any workaround to open the picker on focus?

planyazilim commented 1 year ago

I hope there will be solution about this bug soon. Almost every App uses DatePicker and I am sure many of troubling this issue.

ralphmagnette commented 1 year ago

Is there already a solution or workaround for this bug, need to deploy my application on both Apple Store and Google Play?

Ghostbird commented 1 year ago

Related discussion. It's annoying that Github doesn't automatically link these like it does for issues and PRs.

nonoodev commented 1 year ago

Did you find any workaround to open the picker on focus?

The very dirty fix we found was to replace <Picker IsVisible="False x:Name="ItemPicker" ...... /> by <Picker Opacity="0" HeightRequest="1" WidthRequest="1" x:Name="ItemPicker" ...... />

and update our OpenPicker method as following :

private void OpenPicker(object sender, EventArgs e)
{ 
    ItemPicker.Unfocus();
    ItemPicker.Focus();
    // TODO Update when bug will be fixed
}

(we have a TapGestureRecognizer that call the OpenPicker method)

I don't think it's a good way to fix it for production but we had to make it work quickly to continue the development of the app and it's working.

Right now we're still waiting for this to be resolved but we're already thinking to write our own component that will add a "Open" method for the production release. I'll post our code later if it's not yet fixed.

Ghostbird commented 1 year ago

@nonoodev Can you explain how this accomplishes opening the picker, without user interaction? As far as I know the issue is that the code that opens the picker has been removed from the Focus() method in #8913.

From what I can see, you had an ItemPicker that was not rendered (IsVisible="False"), and now you render it transparent. Any tapped picker will open by default. A non-rendered picker is not tappable, but a transparent picker can be tapped. To me it seems as if you code has nothing to do with this issue, and executes some unnecessary code as an aside. I think it would still work the same if you removed the TapGestureRecogniser.

Keep in mind that this issue is about the situation where we want to open the picker without user interaction!

Sergtek commented 1 year ago

I have found a way to open the date picker, Android's native View class (Android.Views) have a method called PerformClick which allows opening the date picker without pressing the DatePicker and TimePicker, I leave you an example of how I did it in case it can help someone in the same situation.

I have made a small example in which I have a DatePicker, when the user clicks on it the date picker appears, when we select a date from the picker and click "OK" the DateSelected event is fired and this is where the magic is done to access the TimePicker Handler and thus be able to access the native "PerformClick" method to open the TimePicker time selector without having to click on it:

XAML:

        <StackLayout
            HorizontalOptions="CenterAndExpand"
            VerticalOptions="CenterAndExpand">
            <DatePicker 
                x:Name="datePicker"
                DateSelected="datePicker_DateSelected"
                BackgroundColor="White"
                TextColor="Black"
                FontSize="20"
                WidthRequest="200"
                HeightRequest="200">
            </DatePicker>

            <TimePicker 
                x:Name="timePicker"
                IsVisible="False"/>
        </StackLayout>

Code-behind:

    private void datePicker_DateSelected(object sender, DateChangedEventArgs e)
    {
#if ANDROID
        var handler = timePicker.Handler as ITimePickerHandler;
        handler.PlatformView.PerformClick();
#endif
    }

Image: fixFocusIssue

echolumaque commented 1 year ago

Here we go again folks :)

YakushenkoES commented 7 months ago

Is there any solution for Windows?

JimmyPun610 commented 6 months ago

Still an issue in .NET8. https://github.com/dotnet/maui/issues/8946#issuecomment-1446178827 works but there is another problem. Since the focus and unfocus event do not fire at all, there is no way to do any action on dialog onclose

kelputoo123 commented 6 months ago

They really need to fix this, i can't go further in my app without this thing. I will try to use a different datepicker control from syncfusion or something like that, must work.

Sergtek commented 5 months ago

Still an issue in .NET8. #8946 (comment) works but there is another problem. Since the focus and unfocus event do not fire at all, there is no way to do any action on dialog onclose

Yes you can detect the closing of the DatePicker dialog, not directly with the unfocus event because the MAUI abstraction layer currently does not allow it, but you can create a handler and access the native DatePicker close events in the Android case I believe they are Cancel (handles cancel/close event) and Dismiss (handles when the dialogue is closed under any circumstance), if you are not familiar with Maui handlers it still has support for custom renderer in case it is easier for you.

Akinpellumie commented 3 months ago

I have found a way to open the date picker, Android's native View class (Android.Views) have a method called PerformClick which allows opening the date picker without pressing the DatePicker and TimePicker, I leave you an example of how I did it in case it can help someone in the same situation.

I have made a small example in which I have a DatePicker, when the user clicks on it the date picker appears, when we select a date from the picker and click "OK" the DateSelected event is fired and this is where the magic is done to access the TimePicker Handler and thus be able to access the native "PerformClick" method to open the TimePicker time selector without having to click on it:

XAML:

        <StackLayout
            HorizontalOptions="CenterAndExpand"
            VerticalOptions="CenterAndExpand">
            <DatePicker 
                x:Name="datePicker"
                DateSelected="datePicker_DateSelected"
                BackgroundColor="White"
                TextColor="Black"
                FontSize="20"
                WidthRequest="200"
                HeightRequest="200">
            </DatePicker>

            <TimePicker 
                x:Name="timePicker"
                IsVisible="False"/>
        </StackLayout>

Code-behind:

    private void datePicker_DateSelected(object sender, DateChangedEventArgs e)
    {
#if ANDROID
        var handler = timePicker.Handler as ITimePickerHandler;
        handler.PlatformView.PerformClick();
#endif
    }

Image: fixFocusIssue fixFocusIssue

This works for me even to trigger datepicker. For both iOS and Android, see below implementation

#if ANDROID
        var handler = datePicker.Handler as IDatePickerHandler;
        handler.PlatformView.PerformClick();
#endif

#if IOS
        var iosHandler = datePicker.Handler as IDatePickerHandler;
        iosHandler.PlatformView.ResignFirstResponder();
#endif
mattleibow commented 3 months ago

I think for a11y reasons, we cannot/should not open the picker. If you are navigating the screen using TalkBack, then suddenly it goes from a form to a date picker and then you are lost.

This must be a separate API where the dev can decide when/if to show the picker.

Ghostbird commented 3 months ago

I think for a11y reasons, we cannot/should not open the picker. If you are navigating the screen using TalkBack, then suddenly it goes from a form to a date picker and then you are lost.

This must be a separate API where the dev can decide when/if to show the picker.

Agreed. My use case currently is only a date+time picker where I show the time picker when a date is picked.