[英]Unable to hide Android Keyboard on Android 9
创建一个应用程序,点击 webview 输入字段,必须执行一个操作。 捕获并启动选定的操作工作正常,但由于它是通过单击输入字段启动的,因此需要键盘。 在 Android < 版本 9 上,我当前的代码可以很好地隐藏键盘,但在 Android 版本 9 上,它没有。
我已经尝试了这篇文章中被认为是最佳答案的所有庄园或组合,但没有一个适用于我在 Android 9 上的应用程序
下面是我的 MainActivity 中的一些代码,其中创建了我的键盘服务实现的实例。 MainActivity 代码之后是我为 android 制作的键盘服务实现。
[Activity(Label = "Dental.App", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, WindowSoftInputMode = SoftInput.StateAlwaysHidden) ]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
...
DependencyService.Get<IServiceCollection>().SetKeyboardService(new KeyboardService(this, GetInputMethodManager()));
...
}
public InputMethodManager GetInputMethodManager()
{
return (InputMethodManager)GetSystemService(Context.InputMethodService);
}
}
public class KeyboardService : IKeyboardService
{
private InputMethodManager inputMethodManager;
private readonly object mainActivity;
public KeyboardService(object activity, InputMethodManager methodManager)
{
mainActivity = activity;
inputMethodManager = methodManager;
}
public bool IsKeyboardShown => inputMethodManager.IsAcceptingText;
public void HideKeyboard()
{
if (inputMethodManager == null || !(mainActivity is Activity activity)) return;
Logging.Log(LogType.Information, $"Attempting to Hide Keyboard via 1st method...");
//var view = activity.CurrentFocus;
var view = activity.FindViewById(Android.Resource.Id.Content).RootView;
if (view == null) Logging.Log(LogType.Warning, $"Failed to get View from Activity...");
var token = view?.WindowToken;
if (token == null) Logging.Log(LogType.Warning, $"Failed to get Token from View...");
var success = inputMethodManager.HideSoftInputFromWindow(token, HideSoftInputFlags.None);
Logging.Log(LogType.Information,
$"{nameof(inputMethodManager.HideSoftInputFromWindow)} returned => {success}");
if(success) view?.ClearFocus();
if (!IsKeyboardShown)
{
view?.ClearFocus();
return;
}
Logging.Log(LogType.Warning,
$"Failed to Hide Keyboard via {nameof(inputMethodManager.HideSoftInputFromWindow)}...");
HideKeyboardAttemptTwo(activity);
}
private void HideKeyboardAttemptTwo(Activity activity)
{
Logging.Log(LogType.Information, $"Attempting to Hide Keyboard via 2nd method...");
//var view = activity.CurrentFocus;
var view = activity.FindViewById(Android.Resource.Id.Content).RootView;
if (view == null) Logging.Log(LogType.Warning, $"Failed to get View from Activity...");
var token = view?.WindowToken;
if (token == null) Logging.Log(LogType.Warning, $"Failed to get Token from View...");
inputMethodManager.ToggleSoftInputFromWindow(token, ShowSoftInputFlags.None, HideSoftInputFlags.None);
if (!IsKeyboardShown)
{
view?.ClearFocus();
return;
}
Logging.Log(LogType.Warning, $"Failed to Hide Keyboard via {nameof(inputMethodManager.ToggleSoftInputFromWindow)}...");
}
public void ReInitializeInputMethod()
{
inputMethodManager = InputMethodManager.FromContext((Context) mainActivity);
}
没有一个空检查返回真,即没有任何东西是空的。 方法 HideKeyboard 中名为 success 的变量在 99% 的 Android 版本 9 上调用它的情况下返回 false。在 1% 的情况下为 true,键盘仍处于打开状态。 如果键盘仍然显示在 HideKeyboard 的末尾,则代码尝试通过在 HideKeyboardAttemptTwo 方法中切换它来关闭键盘。 在 Android 9 上执行这些方法中的任何一种都不起作用,但是在 Android 7.1 上运行完全相同的代码可以正常工作。
我不完全确定我是否正确实现了 ToggleSoftInputFromWindow 的使用,它旨在仅在键盘打开时才能运行,即始终用于隐藏键盘。
重申我的问题:如何在 Android 9 上成功隐藏键盘。
如果需要任何其他信息,请询问,我会尝试找到并提供它。
我将它用于我的应用程序,试一试
主项目中的接口
namespace *.Services.Interfaces
{
public interface IForceKeyboardDismissalService
{
void DismissKeyboard();
}
}
电话特定代码
using Plugin.CurrentActivity; //Nugget used to get activity
[assembly: Xamarin.Forms.Dependency(typeof(AndroidForceKeyboardDismissalService))]
namespace *.Droid.PhoneSpecific
{
public class AndroidForceKeyboardDismissalService : IForceKeyboardDismissalService
{
public void DismissKeyboard()
{
var imm = InputMethodManager.FromContext(CrossCurrentActivity.Current.Activity.ApplicationContext);
imm?.HideSoftInputFromWindow(CrossCurrentActivity.Current.Activity.Window.DecorView.WindowToken, HideSoftInputFlags.NotAlways);
var currentFocus = CrossCurrentActivity.Current.Activity.CurrentFocus;
if (currentFocus != null && currentFocus is EditText)
currentFocus.ClearFocus();
}
}
}
用法
DependencyService.Get<IForceKeyboardDismissalService>().DismissKeyboard();
让我知道它是否适合你。
为了解决我的问题,我将一些 JavaScript 注入到 Webview 中,在其中我没有聚焦输入字段,然后单击该字段。
在我的 Webview 类中,我创建了一个方法,如果给定元素的字符串 id,它将切换该元素是否获得焦点。 作为第二个输入,可以提供一个布尔值,但默认为 True,以指示您是否只想取消对元素的关注。
public class AdvancedWebView : HybridWebView
{
...
public void ToggleElementFocus(string elementId, bool onlyUnFocus = true)
{
var js = GetJsInvertFocus(elementId, onlyUnFocus);
InjectJavaScript(js);
// Logging.Logging.Log(LogType.Information, $"Injected Javascript => {js}");
}
...
private string GetJsInvertFocus(string elementId, bool onlyUnFocus)
{
var builder = new StringBuilder();
builder.Append($"if (document.getElementById('{elementId}'))");
builder.Append("{");
builder.Append($"var element = document.getElementById('{elementId}');");
builder.Append($"if (element === document.activeElement)");
builder.Append("{");
builder.Append($"element.blur();");
builder.Append("}");
builder.Append($"else if({onlyUnFocus} == False)");
builder.Append("{");
builder.Append($"element.focus();");
builder.Append("}");
builder.Append("}");
return builder.ToString();
}
...
}
我正在从 XLabs 扩展 HybridWebview,因为它已经具有将 JavaScript 注入 Webview 的功能。 这就是我从中获取 InjectJavaScript 方法的地方。
在我的应用程序页面上,使用 Webview,然后当单击元素时,我有一个运行的方法。 要在单击 Webview 时获得单击事件,请查看此链接。 在这个方法中,我从事件参数中找出元素 id 是什么,然后使用这个 id 注入上面显示的 JavaScript,使元素失去焦点,导致键盘根本不出现。 在我的 OnClicked 方法下方可以看到。
public partial class DentalWebPage : AdvancedTabbedPage
{
...
private void DentalWebView_OnClicked(object sender, ClickEvent e)
{
try
{
if (LogUserPosition(sender, e)) return;
SwapToScanningTap();
}
catch (Exception ex)
{
Logging.Log(LogType.Exception,
ex.GetType().Namespace == typeof(BaseException).Namespace
? $"{ex.GetType()} => {ex}"
: $"{ex.GetType()} => {ex.Message}; Stacktrace => {ex.StackTrace}");
}
}
private bool LogUserPosition(object sender, ClickEvent e)
{
if (Config.DebugMode) Logging.Log(LogType.Debug, $"WebView was clicked...");
if (Config.DebugMode) Logging.Log(LogType.Debug, $"Element that was clicked is the following one => {e.Element}");
var success = Enum.TryParse(e.Element.Split(' ')[1].Split('=')[1], out clickedInputId);
if (!success && !(clickedInputId == InputId.MainContent_TextBoxInputStr ||
clickedInputId == InputId.MainContent_TextBoxScanOrder ||
clickedInputId == InputId.MainContent_TextBoxSelectProd ||
clickedInputId == InputId.MainContent_TextBoxStockReturn))
return true;
if (Config.DebugMode && webPageEnding == WebsiteControllers.Stock.ToString().ToLowerInvariant())
Logging.Log(LogType.Debug, $"WebView was clicked while on the stock page...");
return false;
}
private void SwapToScanningTap()
{
PerformOnMainThread(() =>
{
CurrentPage = Children[1];
ScanningToggle.IsToggled = true;
try
{
var isKeyboardShown = services.KeyboardService.IsKeyboardShown;
if (Config.DebugMode) Logging.Log(LogType.Debug, $"IsKeyboardShown returns => {isKeyboardShown}");
DentalWebView.ToggleElementFocus(clickedInputId.ToString());
}
catch (ObjectDisposedException)
{
if (DisposedReattempt) throw;
if (Config.DebugMode)
Logging.Log(LogType.Debug,
$"Input Method has been Disposed; Attempting to reinitialize it and rerun the {nameof(SwapToScanningTap)} method ones again");
DisposedReattempt = true;
services.KeyboardService.ReInitializeInputMethod();
SwapToScanningTap();
}
});
}
...
private void PerformOnMainThread(Action action)
{
try
{
Device.BeginInvokeOnMainThread(action);
}
catch (Exception ex)
{
Logging.Log(LogType.Exception,
ex.GetType().Namespace == typeof(BaseException).Namespace
? $"{ex.GetType()} => {ex}"
: $"{ex.GetType()} => {ex.Message}; Stacktrace => {ex.StackTrace}");
}
}
}
如果您想了解 e.Element 中包含的字符串的格式,请查看之前提供的链接。
随意提出进一步的问题,以防我错过了什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.