使用 Xamarin Forms 在 Android 上快速隐藏和重新出现键盘
Keyboard quickly hides and reappears on Android using Xamarin Forms
我们正在尝试使用 Xamarin Forms 构建一个聊天应用程序,但我们一直在使用 Android 键盘遇到这个恼人的错误。每当点击 "Send" 按钮时,Entry(用于聊天的文本框)上的焦点就会丢失,键盘也会消失。这不是我们想要的,所以我们将这一行添加到 TapGestureRecognizer:
messageEntry.Focus();
但由于某种原因,这种情况发生的速度不够快,而且键盘经常按下并立即再次弹起。这可以防止用户按顺序快速发布多条消息。有人知道如何解决这个问题吗?
这会有点 hack,但您可以分拆一个等待 50 毫秒的异步任务,然后调用主 UI 线程上的 messageEntry.Focus() 行...
感谢@AdamKemp 在此 post 中的回答,这是我的解决方案。如果触摸在我的 EntryStackLayout
范围内(不要忘记创建空的自定义渲染器),那么我不会关闭键盘(如果 CurrentFocus
是 DispatchTouchEvent
就会这样做EditText
).
public class EditorAndButtonReproPage : ContentPage
{
public EditorAndButtonReproPage()
{
BackgroundColor = Color.Gray;
Padding = 50;
var editor = new Editor {HorizontalOptions = LayoutOptions.FillAndExpand};
var editorButton = new Button {Text = "OK", HorizontalOptions = LayoutOptions.End};
var editorLayout = new EntryStackLayout { Orientation = StackOrientation.Horizontal, Children = { editor, editorButton}, VerticalOptions = LayoutOptions.Start};
var entry = new ExtendedEntry { Placeholder = "Entry", HorizontalOptions = LayoutOptions.FillAndExpand };
var entryButton = new Button { Text = "OK", HorizontalOptions = LayoutOptions.End };
var entryLayout = new EntryStackLayout { Orientation = StackOrientation.Horizontal, Children = { entry, entryButton }, VerticalOptions = LayoutOptions.Start };
Content = new StackLayout {Children = {editorLayout, entryLayout}};
}
}
并在 MainActivity
中:
private bool _ignoreNewFocus;
public override bool DispatchTouchEvent(MotionEvent e)
{
var currentView = CurrentFocus;
var parent = currentView?.Parent?.Parent;
var entryStackLayout = parent as EntryStackLayout;
if (entryStackLayout != null)
{
var entryLayoutLocation = new int[2];
entryStackLayout.GetLocationOnScreen(entryLayoutLocation);
var x = e.RawX + entryStackLayout.Left - entryLayoutLocation[0];
var y = e.RawY + entryStackLayout.Top - entryLayoutLocation[1];
var entryStackLayoutRect = new Rectangle(entryStackLayout.Left, entryStackLayout.Top, entryStackLayout.Width, entryStackLayout.Height);
_ignoreNewFocus = entryStackLayoutRect.Contains(x, y);
}
var result = base.DispatchTouchEvent(e);
_ignoreNewFocus = false;
return result;
}
public override Android.Views.View CurrentFocus => _ignoreNewFocus ? null : base.CurrentFocus;
我们正在尝试使用 Xamarin Forms 构建一个聊天应用程序,但我们一直在使用 Android 键盘遇到这个恼人的错误。每当点击 "Send" 按钮时,Entry(用于聊天的文本框)上的焦点就会丢失,键盘也会消失。这不是我们想要的,所以我们将这一行添加到 TapGestureRecognizer:
messageEntry.Focus();
但由于某种原因,这种情况发生的速度不够快,而且键盘经常按下并立即再次弹起。这可以防止用户按顺序快速发布多条消息。有人知道如何解决这个问题吗?
这会有点 hack,但您可以分拆一个等待 50 毫秒的异步任务,然后调用主 UI 线程上的 messageEntry.Focus() 行...
感谢@AdamKemp 在此 post 中的回答,这是我的解决方案。如果触摸在我的 EntryStackLayout
范围内(不要忘记创建空的自定义渲染器),那么我不会关闭键盘(如果 CurrentFocus
是 DispatchTouchEvent
就会这样做EditText
).
public class EditorAndButtonReproPage : ContentPage
{
public EditorAndButtonReproPage()
{
BackgroundColor = Color.Gray;
Padding = 50;
var editor = new Editor {HorizontalOptions = LayoutOptions.FillAndExpand};
var editorButton = new Button {Text = "OK", HorizontalOptions = LayoutOptions.End};
var editorLayout = new EntryStackLayout { Orientation = StackOrientation.Horizontal, Children = { editor, editorButton}, VerticalOptions = LayoutOptions.Start};
var entry = new ExtendedEntry { Placeholder = "Entry", HorizontalOptions = LayoutOptions.FillAndExpand };
var entryButton = new Button { Text = "OK", HorizontalOptions = LayoutOptions.End };
var entryLayout = new EntryStackLayout { Orientation = StackOrientation.Horizontal, Children = { entry, entryButton }, VerticalOptions = LayoutOptions.Start };
Content = new StackLayout {Children = {editorLayout, entryLayout}};
}
}
并在 MainActivity
中:
private bool _ignoreNewFocus;
public override bool DispatchTouchEvent(MotionEvent e)
{
var currentView = CurrentFocus;
var parent = currentView?.Parent?.Parent;
var entryStackLayout = parent as EntryStackLayout;
if (entryStackLayout != null)
{
var entryLayoutLocation = new int[2];
entryStackLayout.GetLocationOnScreen(entryLayoutLocation);
var x = e.RawX + entryStackLayout.Left - entryLayoutLocation[0];
var y = e.RawY + entryStackLayout.Top - entryLayoutLocation[1];
var entryStackLayoutRect = new Rectangle(entryStackLayout.Left, entryStackLayout.Top, entryStackLayout.Width, entryStackLayout.Height);
_ignoreNewFocus = entryStackLayoutRect.Contains(x, y);
}
var result = base.DispatchTouchEvent(e);
_ignoreNewFocus = false;
return result;
}
public override Android.Views.View CurrentFocus => _ignoreNewFocus ? null : base.CurrentFocus;