Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] When a user taps off of an input control the keyboard no longer closes #12002

Closed
1 task
PureWeen opened this issue Dec 9, 2022 · 19 comments · Fixed by #16530
Closed
1 task

[Android] When a user taps off of an input control the keyboard no longer closes #12002

PureWeen opened this issue Dec 9, 2022 · 19 comments · Fixed by #16530
Assignees
Labels
fixed-in-8.0.0-rc.1.9171 Look for this fix in 8.0.0-rc.1.9171 legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert p/1 Work that is critical for the release, but we could probably ship without platform/android 🤖 t/bug Something isn't working

Comments

@PureWeen
Copy link
Member

PureWeen commented Dec 9, 2022

Description

Copied from #6933 (comment)

In XF when you click/tapped outside of a focused entry the entry would lose focus and the keyboard would close. This behavior wasn't copied over to MAUI because the implementation on XF was very wrong and broke accessibility.

If we decide to "fix" this for MAUI .NET 7 we should not implement the "Unfocus" behavior and only make it so that it closes the keyboard.

Reasons to fix

  • this is how it works in Forms
  • we already have code for iOS that's custom that does this so it's compelling to do this in Forms so we can match behavior for users migrating.
  • we can make it work in a way that doesn't break accessibility like it did in XF 
  • We can make the behavior match Forms in NET7 and then provide an API in NET8 that lets users toggle this behavior on/off for iOS and Android
  • Users currently don't have an easy way to enable this behavior so as to match with XF. At a later point we might have enough API surface for users to do this themselves easily but currently they do not.

Reasons not to fix for .NET 7

  • This is not a standard feature of the platform and anytime we modify the platform behavior that will typically have consequences that we aren't even aware of.
  • We can leave the behavior how this is for now in NET7 and provide an API in NET8 that lets users toggle this behavior on/off for iOS and Android
  • By default on iOS/Android if an input field has focus and then you click on a button the keyboard will not close. This is the desired behavior in a lot of scenarios (think chat app). If we add this behavior back into .NET 7 this will change the current behavior on Android so it might be better to wait until we can implement Add TextInput property so users can enable/disable if they want tapping outside on an input field to close the keyboard #12003

Concerns

The way this behavior worked in XF was to make the entire page clickable which made apps completely inaccessible. Anybody wanting to pass WCAG certification with an XF app were forced to write custom code to disable this behavior. The only place where I've seen this behavior is if the area you click off to is interactable in some format. For example, the maps app if you click off to the results but if you test with the WIFI app or contacts app they don't work like this. If you want to add this behavior yourself I think this would be the best way to go about it https://stackoverflow.com/a/28939113 so you don't confuse TalkBack.

I think we need to flesh out the use cases here a bit more so we can provide guidance or additional APIs to give people the ability to make these choices if they want to but we're not going to make this the default behavior unless provided some examples that are accessible and preferable over the default Android behavior or if it can demonstrated that .NET MAUI breaks Android platform defaults.

Steps to Reproduce

  • click on an entry
  • click off the entry
  • keyboard is still open

Link to public reproduction project repository

N/A

Version with bug

6.0 Release Candidate 2 or older

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android

Did you find any workaround?

Relevant log output

No response

@PureWeen PureWeen added the t/bug Something isn't working label Dec 9, 2022
@Eilon Eilon added the legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor label Dec 9, 2022
@jfversluis jfversluis added this to the Backlog milestone Dec 12, 2022
@ghost
Copy link

ghost commented Dec 12, 2022

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.

@pulmuone
Copy link

I am using Android Entry Keyboard bug fixed like this.
https://github.com/pulmuone/MauiAndroidKeyboard

@redcassio
Copy link

redcassio commented Dec 19, 2022

public class MainActivity : MauiAppCompatActivity
{
public override bool DispatchTouchEvent(MotionEvent e)
    {
        if (e.Action == MotionEventActions.Down)
        {
            var view = CurrentFocus;
            if (view is EditText editText)
            {
                editText.ClearFocus();
                InputMethodManager imm = (InputMethodManager)GetSystemService(Context.InputMethodService);
                imm.HideSoftInputFromWindow(view.WindowToken, 0);
            }
        }

        return base.DispatchTouchEvent(e);
    }
}

Android is currently using it temporarily.
I hope it will be revised as soon as possible.

@PureWeen
Copy link
Member Author

PureWeen commented Dec 19, 2022

I am using Android Entry Keyboard bug fixed like this. https://github.com/pulmuone/MauiAndroidKeyboard

@pulmuone
Why not use a Handler?

@pulmuone
Copy link

I pushed again using Handler in HandlerEntryView2.xaml.

@taz4270
Copy link

taz4270 commented Dec 29, 2022

public class MainActivity : MauiAppCompatActivity
{
public override bool DispatchTouchEvent(MotionEvent e)
    {
        if (e.Action == MotionEventActions.Down)
        {
            var view = CurrentFocus;
            if (view is EditText editText)
            {
                editText.ClearFocus();
                InputMethodManager imm = (InputMethodManager)GetSystemService(Context.InputMethodService);
                imm.HideSoftInputFromWindow(view.WindowToken, 0);
            }
        }

        return base.DispatchTouchEvent(e);
    }
}

Android is currently using it temporarily. I hope it will be revised as soon as possible.

I make one solution based on this one but without keyboard flicker everytime you repress it

public class MainActivity : MauiAppCompatActivity, IOnTouchListener
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            Window.DecorView.ViewTreeObserver.GlobalFocusChange += FocusChanged;
        }

        void FocusChanged(object sender, ViewTreeObserver.GlobalFocusChangeEventArgs e)
        {
            if (e.OldFocus is not null)
            {
                e.OldFocus.SetOnTouchListener(null);
            }

            if (e.NewFocus is not null)
            {
                e.NewFocus.SetOnTouchListener(this);
            }


            if (e.NewFocus is null && e.OldFocus is not null)
            {
                InputMethodManager imm = InputMethodManager.FromContext(this);

                IBinder wt = e.OldFocus.WindowToken;

                if (imm is null || wt is null)
                    return;

                imm.HideSoftInputFromWindow(wt, HideSoftInputFlags.None);
            }
        }

        public override bool DispatchTouchEvent(MotionEvent ev)
        {
            bool dispatch = base.DispatchTouchEvent(ev);

            if (ev.Action == MotionEventActions.Down && CurrentFocus is not null)
            {
                if (!KeepFocus)
                    CurrentFocus.ClearFocus();
                KeepFocus = false;
            }

            return dispatch;
        }

        bool KeepFocus { get; set; }

        bool OnTouch(View v, MotionEvent e)
        {

            if (e.Action == MotionEventActions.Down && CurrentFocus == v)
                KeepFocus = true;

            return v.OnTouchEvent(e);
        }

        bool IOnTouchListener.OnTouch(View v, MotionEvent e) => OnTouch(v, e);
    }

The explanation is simple, if focused it will set the touch listener
on receiving the touch it changed the flag KeepFocus to true

If KeepFocus is not set, the dispatch touch will unfocus
If Unfocus the keyboard hides

There is still an issue which is if you touch another entry, it will still flicker but every other instance it working fine, might need to tune somthing to make it work at 100%

Hope I could be of some use

@PureWeen
Copy link
Member Author

I've put together a behavior here that seems to work alright and cover most cases. T

https://github.com/PureWeen/ShanedlerSamples/tree/main/ShanedlerSamples/Library

<Entry Placeholder="Text Field" Text="Starting text" WidthRequest="300">
                <Entry.Behaviors>
                    <local:TapToCloseBehavior></local:TapToCloseBehavior>
                </Entry.Behaviors>

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

        return builder.Build();
    } 
  • This lets you opt in some fields but not all fields.
  • Handles cases where you re-tap on the same entry and it won't close the keyboard
  • Covers cases where the keyboard might flicker.
  • Also handles if the user scrolls. So, if the user scrolls the screen instead of taps the screen than it doesn't close the keyboard.

Some version of this will probably make it into the keyboard

@eynerdevp
Copy link

this still doesn't work in .net 7

@SaeedAtEposcompany
Copy link

Can you tell when this will be fixed?

@Buryyy
Copy link

Buryyy commented Jan 12, 2023

Same issue with latest .NET MAUI

@PureWeen
Copy link
Member Author

Out of curiosity, why do most of the solutions you all have worked up here also clear focus? Why isn't just closing the keyboard sufficient? It feels jarring to the user to just completely remove/change the focus unless that's a clear transition for the user.

For example, here's a gif of how ClearFocus works on an API 21 device.

2023-01-17_11-48-56

It just moves focus to the top entry. I tested on API 30+ and on those it clears the focus but that still feels confusing. Clearing the focus resets focus to zero so now if the user has a keyboard attached, they are in an unexpected place.

The only way (that I know of)) to completely clear the focus from the entries is to move the focus to a non-interactive element. So, in Xamarin.Forms we made the page itself clickable/focusable. Making a non-interactive element focusable makes your app unusably confusing for people that are hard of site or for keyboard users.

If someone can provide a sample or a platform/popular app that demonstrates this behavior, can you please link to it here? The closest I can find is google maps, where clicking the results closes the keyboard, but that's because it's moving the focus to the search results. Which makes sense.

iOS handles this behavior slightly "better". In iOS if you "clear focus" it remembers where you were.

To be clear, we are adding a way to click outside an entry and close the keyboard it just won't clear the focus.

In the meantime, please test with my behaviors.
#12002 (comment)

let me know how well they work/don't work.

@taz4270
Copy link

taz4270 commented Jan 17, 2023

Out of curiosity, why do most of the solutions you all have worked up here also clear focus? Why isn't just closing the keyboard sufficient? It feels jarring to the user to just completely remove/change the focus unless that's a clear transition for the user.

For example, here's a gif of how ClearFocus works on an API 21 device.

2023-01-17_11-48-56 2023-01-17_11-48-56

It just moves focus to the top entry. I tested on API 30+ and on those it clears the focus but that still feels confusing. Clearing the focus resets focus to zero so now if the user has a keyboard attached, they are in an unexpected place.

The only way (that I know of)) to completely clear the focus from the entries is to move the focus to a non-interactive element. So, in Xamarin.Forms we made the page itself clickable/focusable. Making a non-interactive element focusable makes your app unusably confusing for people that are hard of site or for keyboard users.

If someone can provide a sample or a platform/popular app that demonstrates this behavior, can you please link to it here? The closest I can find is google maps, where clicking the results closes the keyboard, but that's because it's moving the focus to the search results. Which makes sense.

iOS handles this behavior slightly "better". In iOS if you "clear focus" it remembers where you were.

To be clear, we are adding a way to click outside an entry and close the keyboard it just won't clear the focus.

In the meantime, please test with my behaviors. #12002 (comment)

let me know how well they work/don't work.

The problem isnt the views themselves but when an entry is a children of a scrollview (for example).
If you make the same view you are using where but using a ScrollView as the main content for the page, the same behavior will not work

@PureWeen
Copy link
Member Author

The problem isnt the views themselves but when an entry is a children of a scrollview (for example). If you make the same view you are using where but using a ScrollView as the main content for the page, the same behavior will not work

Are you referring to the behaviors I have in my sample project?

They work fine when nested in a ScrollView. The sample I'm testing them on has them nested in ScrollView.

image

@taz4270
Copy link

taz4270 commented Jan 18, 2023

you can try to use my example of the issue here https://github.com/taz4270/ScrollNFocus-Example
I know that it isnt working for me, but its very similar from mine
Just make sure to activate the scrollView on BlaPage which is commented

PS: Im using the latest .NET 7 MAUI (7.0.52)

@PureWeen
Copy link
Member Author

you can try to use my example of the issue here https://github.com/taz4270/ScrollNFocus-Example I know that it isnt working for me, but its very similar from mine Just make sure to activate the scrollView on BlaPage which is commented

PS: Im using the latest .NET 7 MAUI (7.0.52)

It looks like you've rolled your own solution here.

Did you try with the behaviors I created?
https://github.com/PureWeen/ShanedlerSamples/tree/main/ShanedlerSamples/Library

@PureWeen PureWeen self-assigned this Jan 18, 2023
@PureWeen
Copy link
Member Author

PureWeen commented Feb 6, 2023

Proposal discussion to release this behavior as part of the community toolkit

CommunityToolkit/Maui#967

This way we can provide the behavior faster and then also refine/add to it out of band from MAUI.

@NguyenBaTu1
Copy link

Does not work with Community Toolkit Popup.

@Geethu-AdhikarVeedu
Copy link

Window.DecorView.ViewTreeObserver.GlobalFocusChange += FocusChanged;

This works fine if i click outside an entry. But it breaks the functionality of the clear button in an entry. On click of clear button, entry gets focused again and doesn't clear the text.

@samhouts samhouts added the p/1 Work that is critical for the release, but we could probably ship without label Aug 28, 2023
@samhouts samhouts added the migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert label Oct 5, 2023
@samhouts samhouts modified the milestones: Backlog, .NET 9 Planning Oct 5, 2023
@PureWeen
Copy link
Member Author

Fixed by #16530

@PureWeen PureWeen closed this as not planned Won't fix, can't repro, duplicate, stale Oct 10, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Nov 10, 2023
@samhouts samhouts added the fixed-in-8.0.0-rc.1.9171 Look for this fix in 8.0.0-rc.1.9171 label Dec 19, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
fixed-in-8.0.0-rc.1.9171 Look for this fix in 8.0.0-rc.1.9171 legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert p/1 Work that is critical for the release, but we could probably ship without platform/android 🤖 t/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.