Mobile: How to dismiss keyboard with cancellation token after certain duration
The concept is very simple:
I started with static variable: CancellationTokenSource.
Instantiate the variable outside the 'TextChanged' event.
Within the 'text changed' event, cancel the token every time when user enter a text.
Reinitialise the cancellationTokenSource, because you need it for the delay task, a task to dismiss the keyboard.
Before that, I have a custom search view, which is a view that consists of an entry field with a magnifying glass, plus a binding to activity indicator (loading spinner).
Instead of using the normal element 'entry', I have a custom element here:
public class SearchEntry : Entry {}
And, here is my custom search view:
public class SearchView : StackLayout
{
public event EventHandler<TextChangedEventArgs> TextChanged;
public static readonly BindableProperty IndicatorRunningProperty =
BindableProperty.Create("IndicatorRunning", typeof(bool), typeof(SearchView), false);
public bool IndicatorRunning
{
get { return (bool)GetValue(IndicatorRunningProperty); }
set { SetValue(IndicatorRunningProperty, value); }
}
private ActivityIndicator indicator;
public Entry entry;
public new event EventHandler<FocusEventArgs> Focused;
public new event EventHandler<FocusEventArgs> Unfocused;
public SearchView() {
entry = new SearchEntry () {
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Center,
BackgroundColor = Color.White,
Placeholder = string.Format ("Search for someone"),
};
entry.TextChanged += (object sender, TextChangedEventArgs e) => {
if (TextChanged != null) {
TextChanged (this, e);
}
};
entry.Focused += (object sender, FocusEventArgs e) => {
if(Focused != null) {
Focused(this, e);
}
};
entry.Unfocused += (object sender, FocusEventArgs e) => {
if(Unfocused != null) {
Unfocused(this, e);
}
};
indicator = new ActivityIndicator () {
WidthRequest = 27,
HeightRequest = 27,
VerticalOptions = LayoutOptions.CenterAndExpand,
};
indicator.SetBinding (ActivityIndicator.IsRunningProperty, new Binding("IndicatorRunning", BindingMode.TwoWay,source:this));
var image = new Image () {
Source = "ic_search.png",
HeightRequest = 24,
WidthRequest = 24
};
var searchEntryStack = new RoundedStackLayout () {
BackgroundColor = Color.White,
CornerRadius = 5f,
HeightRequest = 27,
HorizontalOptions = LayoutOptions.FillAndExpand,
Orientation = StackOrientation.Horizontal,
Padding = new Thickness (10, 0, 10, 0),
Spacing = Device.OnPlatform (10, 0, 0),
Children = { image, entry, indicator }
};
HorizontalOptions = LayoutOptions.FillAndExpand;
BackgroundColor = StyleHelpers.NavigationPageBgColor;
Padding = new Thickness (20, 10, 20, 10);
Spacing = 0;
HeightRequest = 47;
Orientation = StackOrientation.Horizontal;
Children.Add (searchEntryStack);
}
new public void Unfocus() {
entry.Unfocus ();
}
public void Clear() {
entry.Text = string.Empty;
}
}
Cool, over here is the core of how to use the token cancellation source to dismiss keyboard after certain interval or duration:
Declare a static variable first:
public static CancellationTokenSource tokenSource;
tokenSource = new CancellationTokenSource();
searchView.TextChanged += (sender, e) => {
//Do something here....
//Everytime when user press, then cancel the token. Then Re-init the token.
//Create a task that will complete after time delay with the cancellation token.
tokenSource.Cancel();
tokenSource = new CancellationTokenSource();
var unfocusTask = Task.Delay(3000, tokenSource.Token);
unfocusTask.ContinueWith(t=>{
if (!t.IsCanceled){
Device.BeginInvokeOnMainThread(()=>{
searchView.Unfocus();
});
}
});
};