Open bzd3y opened 3 months ago
Hi I'm an AI powered bot that finds similar issues based off the issue title.
Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!
Note: You can give me feedback by thumbs upping or thumbs downing this comment.
Thanks, but those issues don't help. I had already seen most of them before submitting my issue (most/all of them are not exactly the same anyway). And #21053 isn't open, it is closed, so I'm not sure what is going on there.
I cannot repro this issue on the latest 17.11.0 Preview 5.0 (8.0.70& 8.0.61). I provided the screen recording and repro project. If it does not match what you described, please provide your sample project and I will verify it again.
Thanks @ninachen03. I tried on 8.0.70, but that was in VS 2022 17.10.4. But I wouldn't think the VS version would matter, right?
Either way, this is reassuring. Let me see if there is something going on with my packages.
Are you seeing the same thing with an Editor? Because that is the actual view I was using.
@ninachen03 I noticed that it looks like you may have tested on Windows, rather than Android, which might explain the difference in behavior. I could also be mistaken, so apologies if I'm incorrect.
@PureWeen thoughts?
Thank you for your detailed information. I reproduced it at Android platform using the same sample on 17.11.0 Preview 5.0
@MisterAcoustic Good catch! I wasn't paying attention and just thought that was the Android emulator.
@ninachen03 Thanks for the reproduction video.
@mattleibow Just to be clear, this happens on the Editor as well. I don't know if that matters for the labels.
Same issue reproduced in MAC Os also
@mattleibow @PureWeen what is the status here? This is still happening in SR9 and seems like a pretty major issue! Did you find any workarounds @bzd3y?
Agreed that this is causing weird problems in our application. If I'm focused in a text Entry and exit the page, the keyboard is still showing on the new page (iOS). It is also happening using the SearchBar control (not dismissing keyboard)
@reid-kirkpatrick I haven't had the time to work on a workaround until now. But now I'm at the point where I can and need to try to figure something out.
I finally got around to looking at this. As a small update, I have figured out that the issue isn't with the Entry
/Editor
/other view. The issue is with the Button
and Android not handling focus/clicking very well. I would argue incorrectly.
When the button has FocusableInTouchMode
set to true then the Entry.Unfocused
works correctly. But then the problem is that because the button is now "focusable in touch mode" it is no longer clickable when it gets focus. I.e., touching/clicking it once gives it focus and doesn't register the click.
My current workaround involves firing the Clicked()
manually when the button gets focus, but that seems less than ideal because some apps might not expect the button to be clicked when it gets focus, like if is done programmaticaly, and it also changes the button's appearance so that it stays focused. I'm looking at trying to change that to fire it on Touch
, but it appears that Focus
, Touch
and Click
all interfere with each other, at least on Android (that probably being the larger problem here).
For example, it looks like setting a Touched
event causes FocusableInTouchMode
to be ignored.
And clearing the focus on the element after Clicked()
is called causes Clicked()
to be called twice. I guess because now that the focus is cleared the original click event fires. But the strange thing is that if I don't call Clicked()
manually, then a clicked event isn't fired at all.
For anybody (@reid-kirkpatrick) interested in the current workaround, here is the code:
ButtonHandler.Mapper.AppendToMapping("UnfocusFix", (h, b) =>
{
h.PlatformView.FocusableInTouchMode = true;
});
ButtonHandler.Mapper.PrependToMapping(nameof(Button.IsFocused), (h, b) =>
{
if (b.IsFocused)
{
b.Clicked();
}
});
Like I said, this isn't an ideal workaround, but it might get people past this for the time being. In the meantime, I'll see if I can find something better.
Okay, I think I have something better:
ViewHandler.ViewMapper.AppendToMapping("UnfocusFix", (h, v) =>
{
if (v is not ScrollView && h.PlatformView is Android.Views.View view && view.Focusable && (view.FocusableInTouchMode == false))
{
view.Touch += (s, e) =>
{
if (e.Event?.Action == MotionEventActions.Down)
{
view.Context?.GetActivity()?.CurrentFocus?.ClearFocus();
}
e.Handled = false;
};
}
});
This adds a Touch
event to everything that is Focusable
(except for ScrollView
s) and not FocusableInTouchMode
that clears the focus of the currently focused view.
The ScrollView
exemption is there because they are Focusable
, so something like an Entry
inside of a ScrollView
would now lose focus if the user clicks anywhere else in the ScrollView
. Although, that could be a desired behavior. In that case you probably want to change the if
to just if (h.PlatformView is Android.Views.View view)
so that touching any view outside of the current view will cause it to lose focus, though I haven't tested that. Or you may want a handler that sets any "container" view or page to Focusable
.
There may also be views other than ScrollView
that should be excluded, but I can't think of any.
Finally, this is obviously specific to Android. I haven't seen this issue in iOS, but if it does happen then there probably needs to be a similar handler. At some point I will be checking/testing that.
Just adding support to this issue and the fact that it appears to be creating problems for us migrating an app from Xamarin Forms. The responses on other tickets from Microsoft PMs (which are quickly subsequently closed after claiming to be open to learning more about developers' needs) seem inadequate and dismissive of developer concerns.
HideSoftInputOnTapped
only appears to be available on ContentPages which is not helpful if you are using Popups. This is on top of the problem if you are pressing on buttons it also doesn't work as noted by @bzd3y 's original post here.
I will have to look at implementing some form of workaround for our app based on contributed suggestions by other external developers in this issue and others (e.g. https://github.com/dotnet/maui/issues/21053#issuecomment-1997163629). Thanks to those of you who are working on solutions / workarounds to this and I really hope Microsoft staff can look at how this might be resolved within MAUI in the longer term.
As a suggestion - could the concept of 'Unfocused' not be bifurcated into two possible contexts:
As long as the developer doesn't / cannot manipulate the focus themselves and is only using the 'lost focus' as a hook for background functionality (such as an auto-save or validation) could the accessibility goals then be preserved?
For anybody (@reid-kirkpatrick) interested in the current workaround, here is the code:
ButtonHandler.Mapper.AppendToMapping("UnfocusFix", (h, b) => { h.PlatformView.FocusableInTouchMode = true; }); ButtonHandler.Mapper.PrependToMapping(nameof(Button.IsFocused), (h, b) => { if (b.IsFocused) { b.Clicked(); } });
Like I said, this isn't an ideal workaround, but it might get people past this for the time being. In the meantime, I'll see if I can find something better.
Just wanted to confirm @bzd3y this fix seems to be the only workaround for me in my app and it does work so thank you very much for posting these fixes I really appreciate it. I am not sure why the other fixes don't work but I suspect it may have something to do with the fact the controls I am using are displayed within a 'Popup'.
@stewartsims You're welcome, I'm glad one of them worked for you.
I wouldn't be surprised if it has to do with them being in the popup. I don't have the time to look at this right now, but when I get a chance I will try to figure something out. In the meantime, a couple of thoughts that might help you get started if you want to try something else.
ContentView
with FocusableInTouchMode
set to true on it and then move focus to that instead of clearing it.FocusableInTouchMode
set to true
or something else in that if
condition might not be met in the popup, so you could try removing the if
completely to see if clearing the focus works at all and if it does, maybe build the condition back to something that works in both situations.FocusableInTouchMode
to true
on whatever views your popup is using. By doing that, your popup will "interfere" with focus like a ScrollView
would if it wasn't being checked for in the if
, but in this case it might be desirable or at least preferrable over focusable buttons. I think what you'd get is that if the user clicks in the popup anywhere outside of a focused view then that view would lose focus.Button
focus is also handled differently. So what you'd get here is that it could help prevent the popup from being dismissed too early by making the user focus to the button first and then click it. So in that case, you could consider removing the mapping to IsFocused
for buttons from the workaround that did work for you entirely and just let them be focusable and "ignore" the first click.Again, when I have more time, I'll try to figure something out. It might help if you give some details on how your popups are working, like what kind of view you are using, etc.
Adding another slightly different solution that I have come up with:
ViewHandler.ViewMapper.AppendToMapping("UnfocusOnTouch", (h, v) =>
{
if (v is not ScrollView && h.PlatformView is AndroidView view && view.Focusable && (view.FocusableInTouchMode == false))
{
view.Touch += (s, a) =>
{
if (a.Event?.Action == MotionEventActions.Down)
{
view.RequestFocusFromTouch();
}
a.Handled = false;
};
}
});
The difference between this code and the last solution is that instead of clearing the focus from the previous view, the view that was touched requests the focus "from touch" and if it gets it, then the focus is taken away from the previous view as would be expected. It is also obviously shorter/simpler code.
So this can be used instead of the other solution if the desired behavior is for the touched view to actually gain focus to take it away from the previous view.
@stewartsims You might want to see if this works for you. The last code might not have worked because focus was being cleared and Android was enforcing the requirement to always have a view with focus. This solution satisfies that requirement, like the solution that worked for you does, but this allows the button to behave normally as far as appearance and clicking is concerned.
Description
I understand there have been issues that addressed this previously, but I still don't think things are working.
Setting
HideSoftInputKeyboard
totrue
does not fix the problem.That may be because I am not clicking outside of the Entry/Editor on the page itself, but another control, like a button.
So what I am seeing is that I can change the focus on the page to an Entry/Editor and enter some text. Then if I click on a button below that, I would expect the Editor's/Entry's
Unfocused
event to fire because the control has lost focus when it switched to the button. From what I gather there is a limitation in Android about at least one control on a page having focus, but it seems that that shouldn't apply here since the button getting focus when it is clicked should satisfy that condition. But I think that even if there wasn't another focusable control then the Entry/EditorUnfocused
event should still fire.As others have said, there are a lot of use cases/UI practices/standards that are broken by not firing the event.
It is also a development or discoverability issue for those views to have an
Unfocused
event that does nothing. Shouldn't they at least be marked as obsolete or deprecated?At the very least the documentation for the event properties should indicate that the event is not implemented at all and won't work.
But, ideally, I think the event should just be fired when the user tries to focus on another control. Note that I said "tries". I think it is perfectly fine if the control can't lose focus that it doesn't actually lose focus. If needed, a developer can check for that within the event. But the event should still fire to indicate that the user tried to change the focus to something else.
Steps to Reproduce
Unfocused
eventUnfocused
event does not get calledLink to public reproduction project repository
No response
Version with bug
8.0.70 SR7
Is this a regression from previous behavior?
Yes, this used to work in Xamarin.Forms
Last version that worked well
Unknown/Other
Affected platforms
Android
Affected platform versions
No response
Did you find any workaround?
No, but it would be nice to know if this behavior could be added through a view handler.
Relevant log output
No response