根据 AI 建议,最简便的方案是在 MainActivity.cs 或是 AndroidManifest.xml 中指定 android:windowSoftInputMode="adjustResize|stateHidden" 然后 android 系统会在打开输入法时建议将应用高度配置为屏幕高度 - 输入法面板高度。 也可设置为 AdjustPan, 输入法打开后, 应用窗口不会调整大小,而是整体上移,给输入法面板留出空间。但在我测试的几台手机上,这个方法并没有起作用。
如下配置,不起作用
# AndroidManifest.xml activity 属性中
android:windowSoftInputMode="adjustResize|stateHidden"
# MainActivity.cs [Activity] 属性中
WindowSoftInputMode = SoftInput.AdjustResize | SoftInput.StateHidden
# MainActivity.cs OnCreate 中
window.SetSoftInputMode(SoftInput.AdjustResize | SoftInput.StateHidden);
目前使用方案为设置应用为全屏,并监听输入法打开和关闭时布局变化事件,在应用中动态改变布局 padding 来适配输入法的高度。发现不同手机会存很大的差异,总结下面的使用方案。
基本配置
设置 AdjustPan|stateHidden,不然无法触发布局事件。不要配置 adjustResize 虽然单独设置它不起作用,但是启用布局改变事件监听时,某些机型上它又生效了,这样系统自动调整高度与手工调整高度同时作用,导致给输入法面板设置了两倍留白。AI 建议使用 AdjustNothing 实测无法触发布局改变事件。
主窗口启动时关闭 Avalonia 的自动调整 TopLevel.SetAutoSafeAreaPadding(this, false);
主窗口启动时关闭沉浸模式
// 设置 SoftInput.AdjustPan
[Activity(WindowSoftInputMode = SoftInput.AdjustPan | SoftInput.StateHidden)]
public class MainActivity : AvaloniaMainActivity<App> {}
MainView.OnLoaded(){
// 关闭自动调整
TopLevel.SetAutoSafeAreaPadding(this, false);
TopLevel? topLevel = TopLevel.GetTopLevel(this);
// 关闭沉浸(全屏铺满)模式(Edge to Edge), 在测试的所有机型上,设置为 true 也没有触发沉浸模式
topLevel?.InsetsManager?.DisplayEdgeToEdgePreference = false;
}
使用 Avalonia 提供监听布局改变事件
# 设置 SoftInput.AdjustPan
[Activity(WindowSoftInputMode = SoftInput.AdjustPan | SoftInput.StateHidden)]
public class MainActivity : AvaloniaMainActivity<App> {}
# 在主窗口的 onload 中配置
// 关闭由 Avalonia 设置安全区域
TopLevel.SetAutoSafeAreaPadding(this, false);
TopLevel? topLevel = TopLevel.GetTopLevel(this);
// 关闭全屏铺满模式(Edge to Edge)
topLevel?.InsetsManager?.DisplayEdgeToEdgePreference = false;
// 如果启用沉浸模式时监听界面布局事件,如状态栏,导航栏留白
// 因为在不同机型上存在差异,所以实际关闭沉浸模式
// topLevel?.InsetsManager?.SafeAreaChanged += (s, args) =>
// {
// _dispatcher.Post(() => {
// Padding = new Thickness(0, 0, 0, args.SafeAreaPadding.Bottom);
// });
// };
// 监听输入法面板布局变化事件
topLevel?.InputPane?.StateChanged += (s, args) => {
// 获取 Avalonia 的渲染缩放比例 (通常等于 Android 的 Density)
// 某些机器上可能要考虑屏幕缩放比例
// double renderScaling = topLevel.RenderScaling;
// double logicalHeight = 1d * args.EndRect.Height / topLevel.RenderScaling;
_dispatcher.Post(() => {
Padding = new Thickness(0, 0, 0, args.EndRect.Height);
});
};
// 初始时将 Padding 设置为 0
Padding = new Thickness(0);
使用 Android 监听布局改变事件
# 设置 SoftInput.AdjustPan
[Activity(WindowSoftInputMode = SoftInput.AdjustPan | SoftInput.StateHidden)]
public class MainActivity : AvaloniaMainActivity<App> {}
# 在主窗口的 onload 中配置
// 关闭由 Avalonia 设置安全区域
TopLevel.SetAutoSafeAreaPadding(this, false);
TopLevel? topLevel = TopLevel.GetTopLevel(this);
// 关闭全屏铺满模式(Edge to Edge)
topLevel?.InsetsManager?.DisplayEdgeToEdgePreference = false;
# 在 MainActivity.OnCreate 中配置
// 获取根视图
View ? rootView = window.DecorView.RootView;
// 使用 AndroidX 的 ViewCompat 监听 Insets
// 开启监听后,在小米手机上强制进入沉浸式模式, 界面被导航栏遮挡
ViewCompat.SetOnApplyWindowInsetsListener(rootView, new OnApplyWindowInsetsListener((view, insets) => {
if (view == null || insets == null) {
return null;
}
// imeInsets.Bottom 输入法面板留白
Insets ? imeInsets = insets.GetInsets(WindowInsetsCompat.Type.Ime());
// systemBars.Top 状态栏留白
// systemBars.Bottom 底部导航栏留白
Insets ? systemBars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars());
return ViewCompat.OnApplyWindowInsets(view, insets);
}));
// 监听处理的辅助类
private class OnApplyWindowInsetsListener(Func < View ? , WindowInsetsCompat ? , WindowInsetsCompat ? > callback): Object, IOnApplyWindowInsetsListener {
public WindowInsetsCompat ? OnApplyWindowInsets(View ? v, WindowInsetsCompat ? insets) {
return callback(v, insets);
}
}
其它
关闭沉浸模式
Avalonia 提供的 topLevel?.InsetsManager?.DisplayEdgeToEdgePreference = true 在所有机型上测试都没有激活,但是一旦使用 ViewCompat.SetOnApplyWindowInsetsListener 监听布局改变事件,在小米手机上就激活了沉浸模式, 不管有没有设置 DisplayEdgeToEdgePreference
关于 AdjustResize
直接设置 AdjustResize 在的有测试机器上都没有效果,但是一旦调用 topLevel?.InputPane?.StateChanged 监听输入法布局事件,在华为手机上就激活了 AdjustResize