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 Unfocused Entry Behavior only gets called when leaving the page #11881

Closed
faceoffers28 opened this issue Dec 5, 2022 · 19 comments
Closed
Labels
area-controls-entry Entry platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Milestone

Comments

@faceoffers28
Copy link

faceoffers28 commented Dec 5, 2022

Description

This works as expected in iOS. In Android, Unfocused only gets called when leaving the page. It does not get called when you leave the Entry field.

Steps to Reproduce

Create an Entry in Xaml.

<Entry Grid.Row="1" x:Name="nameEntry" Grid.Column="0" Placeholder="Enter a screen name." 
      HorizontalOptions="Center" Style="{StaticResource Label_ProfileViewName}"
      Text="{Binding SelectedPlayer.ScreenNameEntry}" TextChanged="entry_name_TextChanged" IsTextPredictionEnabled="false">
     <Entry.Behaviors>
         <local:CheckNameBehavior x:Name="checkScreenName"/>
     </Entry.Behaviors>
</Entry>

Create a Behavior like so.

    public class CheckNameBehavior : Behavior<Entry>
    {
        static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(CheckNameBehavior), false);
        static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;

        public bool IsValid
        {
            get { return (bool)base.GetValue(IsValidProperty); }
            private set { base.SetValue(IsValidPropertyKey, value); }
        }

protected override void OnAttachedTo(Entry bindable)
        {
            bindable.Unfocused += HandleFocusChanged;
        }

protected override void OnDetachingFrom(Entry bindable)
        {
            bindable.Unfocused -= HandleFocusChanged;
        }

async void HandleFocusChanged(object sender, FocusEventArgs e)
        {
            Entry entry = sender as Entry;
        }
}

Link to public reproduction project repository

https://github.com/dotnet/maui/

Version with bug

7.0 (current)

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android 31 with a target of 33

Did you find any workaround?

Nope, there is no workaround.

Relevant log output

No response

@faceoffers28 faceoffers28 added the t/bug Something isn't working label Dec 5, 2022
@PureWeen
Copy link
Member

PureWeen commented Dec 5, 2022

@faceoffers28 this behavior is most likely controlled by the underlying platform. We don't automatically unfocus/focus things when navigation happens.

Can you expand on your use case here?

@PureWeen PureWeen added the s/needs-info Issue needs more info from the author label Dec 5, 2022
@ghost
Copy link

ghost commented Dec 5, 2022

Hi @faceoffers28. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

@faceoffers28
Copy link
Author

@faceoffers28 this behavior is most likely controlled by the underlying platform. We don't automatically unfocus/focus things when navigation happens.

Can you expand on your use case here?

@PureWeen The use case would be checking some text that was entered against a database to see if there is a match. If there is a match, changing the text to red and updating an icon image to indicate an unsuccessful outcome. The Unfocus event works as expected on iOS. It does not work as expected on Android.

@ghost ghost added s/needs-attention Issue has more information and needs another look and removed s/needs-info Issue needs more info from the author labels Dec 5, 2022
@PureWeen
Copy link
Member

PureWeen commented Dec 5, 2022

@faceoffers28 why use focus/unfocus for this? Instead of TextChanged?

@faceoffers28
Copy link
Author

Hello @PureWeen TextChanged fires every time the text changes. It's extremely inefficient. It would result in many API calls to a rest API to check for a result. Is this really the only way to do this?

@Eilon Eilon added the legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor label Dec 6, 2022
@PureWeen PureWeen removed the s/needs-attention Issue has more information and needs another look label Dec 6, 2022
@PureWeen PureWeen added this to the Backlog milestone Dec 6, 2022
@ghost
Copy link

ghost commented Dec 6, 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.

@RsZoli
Copy link

RsZoli commented Feb 14, 2023

@PureWeen please, don't ignore this, it is a serious problem, and not even the shell navigation closes the keyboard!

at least on 7,0 the keyboard can be closed by tapping on the "Done key", on 6.0 that is not possible!

here is a video of the problem: https://imgur.com/a/DxG7pTW

thank you!

@Gekidoku
Copy link

Still an issue.
https://github.com/Gekidoku/UnfocusTest
Start typing in the editor,

Clicking on any other part of the page should trigger Unfocused as it did in xamarin, but it doesnt.

@Gekidoku
Copy link

@PureWeen updated repo, added a page with a viewmodel. where i bind IsFocused. showing same behavior. only unfocusing when i change page through the flyout menu

@RsZoli
Copy link

RsZoli commented Aug 21, 2023

@PureWeen I can confirm that this is still happening! Can you please kindly answer, why is this being ignored for 8 months now? It basically prevents us from migrating to MAUI!

@AramMar
Copy link

AramMar commented Aug 21, 2023

@PureWeen i can also confirm the issue is still existed. and its very important for my app also

@sockstar85
Copy link

I'll also confirm this still still an issue. Makes it really hard to make custom entries or use what we built in Xamarin.Forms in .NET Maui.

@Gekidoku
Copy link

Small note on my unfocus test.
I found that with the viewmodel method and binding to the isfocusedproperty it does trigger if you select a different focusable element.

@kkawormald
Copy link

unfocused is being called on scrolling sometimes with template selectors

@HaimoHeymann
Copy link

Has anybody found a workaround to this issue? (Android only)

@Zhanglirong-Winnie Zhanglirong-Winnie added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed labels Oct 19, 2023
@mattleibow mattleibow changed the title .Net 7 Android Unfocused Entry Behavior only gets called when leaving the page Android Unfocused Entry Behavior only gets called when leaving the page Nov 17, 2023
@mattleibow
Copy link
Member

mattleibow commented Nov 17, 2023

This may be a way to listen to text changes and wait for them to stop:

// used to schedule an update
Timer? timer;

// the buffer
const int TextChangedBuffer = 500; // half a second from the last character to sending the message

async void textEntry_TextChanged(object sender, TextChangedEventArgs e)
{
    var entry = (Entry)sender;

    // create a timer to trigger after the delay
    // the dispatcher is used as the timer returns on a background thread - but may be correct if this is a request to the web
    timer ??= new(_ => Dispatcher.Dispatch(() => UnFocusedLbl.Text = entry.Text));

    // move the timeout forward on each update
    timer.Change(TextChangedBuffer, Timeout.Infinite);
}

@0XDE57
Copy link

0XDE57 commented Dec 22, 2023

We also require a (working) Unfocused event too. TextChanged fires too many events, we only need to know then the user is finished.

Completed may have also worked, but if the user taps on a different entry cell it does not fire Completed(), only when user closes keyboard.

This seems like such a basic functionality, its absence is surprising. Might try the timer method mentioned here but this feels like a hacky workaround.

Edit: the timer method may not be ideal, but works well enough in testing so far...

@Gekidoku
Copy link

Gekidoku commented Jan 12, 2024

I have a small workaround for my case.
I bound the value of the editor to a variable in my viewmodel like so.

 public string Remark
 {
     get
     {
         return MyModel.Remark;
     }
     set
     {
         MyModel.Remark = value;
         RestartTimer();

     }
 }

Then on top of the viewmodel i also have private Timer timer;
Then restart timer is as follows

private void RestartTimer()
{
    // Cancel the previous timer if it exists
    timer?.Dispose();

    // Start a new timer to check for inactivity after 1 seconds
    timer = new Timer(_ =>
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            Update();
        });

       //disposing jic
        timer?.Dispose();
    }, null, 1000, Timeout.Infinite);
}

then update is just a function that sends my remark to the backend.
this works as a workaround for me since im only interested in limiting how many times the update function gets called.
when its directly on textchanged it triggers on every letter and due to the async nature and server hiccups this can mean that an earlier call finishes later than a later call thus overwriting the value of Remark to an earlier value.
this function triggers similarly to textchanged whenever any letter of character gets added to Remarks, but instead of immediately updating it waits a second. if within this second another change happens the timer gets disposed and re set.

EDIT
just noticed 2 posts above.
going to try it like this instead see if i see performance differences. it certainly reads cleaner.

private void RestartTimer()
{
   
    timer ??= new(_ => MainThread.BeginInvokeOnMainThread(() => Update()));
    timer.Change(1000, Timeout.Infinite);
  
}

@rachelkang
Copy link
Member

Hi All,

In developing .NET MAUI, we learned that it is not possible on earlier versions of Android to unfocus an entry. Some control must always be focused. In Xamarin.Forms, this was approached by setting focus on the page layout; unfortunately, this approach created major accessibility issues. For these reasons, .NET MAUI no longer allows for this behavior by default.

If this antipattern can be avoided, we highly recommend using a different approach. If it cannot be avoided, we'd love to learn more about your scenario so that we can better understand your development needs! That being said, we do understand the needs from a migration compatibility standpoint, so for those scenarios, there is a new property that was introduced in .NET 8. Using HideSoftInputOnTapped should do the trick.

@github-actions github-actions bot locked and limited conversation to collaborators Feb 23, 2024
@Eilon Eilon added area-controls-entry Entry and removed legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor labels May 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-controls-entry Entry platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Projects
None yet
Development

No branches or pull requests