unoplatform / uno

Open-source platform for building cross-platform native Mobile, Web, Desktop and Embedded apps quickly. Create rich, C#/XAML, single-codebase apps from any IDE. Hot Reload included! 90m+ NuGet Downloads!!
https://platform.uno
Apache License 2.0
9.08k stars 737 forks source link

Can't press UIAlertController buttons when (soft)keyboard is open #1155

Open pdecostervgls opened 5 years ago

pdecostervgls commented 5 years ago

Current behavior

Pressing on the location of the OK button dismisses the keyboard, but doesn't register as a button press on the UIAlertController.

Expected behavior

When a UIAlertController gets shown, I can enter a value and immediately press cancel or OK without having to press to dismiss the keyboard first.

How to reproduce it (as minimally and precisely as possible)

Repro project: https://github.com/pdecostervgls/repro-uno-uialert-touch

Environment

Nuget Package:

Uno.UI: 1.46.0-dev.1986

Affected platform(s):

Visual Studio

Relevant plugins

Anything else we need to know?

ghuntley commented 5 years ago

That doesn't sound right! Thanks for providing a repro @pdecostervgls. Do you want to take a stab at resolving it? Let me know if you need any help.

pdecostervgls commented 5 years ago

@ghuntley Yeah, i'll take a stab at it, got any idea where I should start?

jeromelaban commented 5 years ago

Once the keyboard as been dismissed, the action buttons work. This is most probably related to the keyboard management code in the Uno Window, which intercepts touches for as a light dismiss layer.

pdecostervgls commented 5 years ago

@jeromelaban I guess that is required behaviour for the Uno Window then, any thougths on how to circumvent this is in certain cases?

pdecostervgls commented 5 years ago

@jeromelaban For non-modal content the touches do pass-through, Are there different handlers for modal content than non-modal?

jeromelaban commented 5 years ago

@pdecostervgls I do not know the specifics for that issue. This is most probably handled in this method:

https://github.com/unoplatform/uno/blob/336c3a4175ec9d1c6e5f960a4343e2d1b7d73d80/src/Uno.UI/Controls/Window.iOS.cs#L97

You can poke around this code to see if there's something to adjust there.

pdecostervgls commented 5 years ago

https://github.com/unoplatform/uno/blob/336c3a4175ec9d1c6e5f960a4343e2d1b7d73d80/src/Uno.UI/Controls/Window.iOS.cs#L138 Seems to get hit twice when clicking on the UIAlertAction view. Once for the UIAlertAction view and then the second time for CLayer. @jeromelaban Am I right in assuming that the return value of HitTest is being passed onto iOS to handle touches?

kazo0 commented 5 years ago

Is this currently being worked on? I can take it if not

pdecostervgls commented 5 years ago

Is this currently being worked on? I can take it if not

@kazo0 Not actively no, feel free to take a stab at it :) Thanks in advance!

kazo0 commented 5 years ago

So it seems like that second call to HitTest() is problematic since we are dismissing the keyboard through the EndEditing() call on the first HitTest() pass. The CALayer that is set to newlyFocusedView on the second pass is the background layer for the UIAlertController. The reason the second pass registers the HitTest() as that CALayer is because the animation occurs that moves all views down once the keyboard is dismissed. So a tap on the OK button will go through the first HitTest() pass and dismiss the keyboard. By the time the second HitTest() occurs, the Alert box has already slid down to the center of the screen since the keyboard is no longer taking up space. Therefore, the tap that was originally on the OK button ultimately registers as a tap ABOVE the OK button on the background layer.

You can confirm this logic by, instead of originally tapping on OK, tap down below where the OK button WILL be once the keyboard dismisses. Tapping on that empty area will dismiss both the keyboard AND the alert at the same time.

kazo0 commented 5 years ago

With that being said, I cannot think of a non-hacky way to fix this at the moment. the HitTest() method gets called by iOS seemingly as many times as iOS wants because HitTest() should technically have no side-effects. Problem is that we are forcing side-effects by dismissing the keyboard at this level. It may make more sense to try and break this out and use another method, perhaps TouchesEnded()? I'm not sure right now.

pdecostervgls commented 5 years ago

@kazo0 Firstly, thanks for looking into this issue, it isn't a blocking issue for my project, but it is a nuisance that we would like to see fixed.

As I have observed earlier, the first time focusedView gets set is with a type of UIAlertAction which is exactly the component which should get "touched". Can't we just pass this along to iOS and then dismiss the keyboard?

kazo0 commented 5 years ago

@pdecostervgls The UIAlertAction is definitely being passed along to iOS on the fist pass of HitTest(), which is still confusing to me as to why the button isn't registering the click. Seems like the second pass for HitTest() takes precedence. I've seen people mention that HitTest() is called multiple times for each subview, others say it is called multiple times because iOS is making slight adjustments to the touch point. Other than forcing the keyboard to not dismiss when the focusedView is any part of a UIAlertController, I'm a little stumped on a non-hacky fix for this.