软键盘与文本框重叠,使其无法访问
本文关键字:访问 重叠 键盘 文本 | 更新日期: 2023-09-27 18:33:11
当输入字段与软键盘重叠时,如何访问 ScrollViewer 中的输入字段?
此方案很容易重现:
-
使用包含一些文本框的滚动查看器创建一个新页面。根据需要制作任意数量的文本框,直到需要滚动页面以到达最后三个文本框。
<ScrollViewer> <StackPanel Orientation="Vertical"> <TextBox Margin="20" /> <TextBox Margin="20" /> <TextBox Margin="20" /> .. <TextBox Margin="20" /> <TextBox Margin="20" /> <TextBox Margin="20" PlaceholderText="3" /> <TextBox Margin="20" PlaceholderText="2" /> <TextBox Margin="20" PlaceholderText="1" /> </StackPanel> </ScrollViewer>
-
启动应用程序并点击"占位符 3"。键盘弹出并与"起搏器 2"和"占位符 1"重叠。
如何改进布局,以便无需一直关闭并重新打开键盘即可访问这些文本框("1"和"2"),以便访问这些文本框?
可以在每个WindowsPhone上找到显示有效解决方案的示例: 设置 => VPN => 启用VPN => 添加新配置文件 => 单击任何文本框,您将看到您可以滚动到布局的每个部分,尽管软键盘已打开。
在这个问题上已经有一段时间了,但对于可能正在寻找一个好解决方案的其他人来说,这就是我所做的。
订阅键盘显示和隐藏事件,并根据键盘显示或隐藏的时间调整滚动查看器的高度。
哈姆勒
<ScrollViewer x:Name="scrlvwrKBScroll" VerticalScrollMode="Enabled">
<StackPanel Orientation="Vertical">
<TextBox Margin="20" />
<TextBox Margin="20" />
<TextBox Margin="20" />
..
<TextBox Margin="20" />
<TextBox Margin="20" />
<TextBox Margin="20" PlaceholderText="3" />
<TextBox Margin="20" PlaceholderText="2" />
<TextBox Margin="20" PlaceholderText="1" />
</StackPanel>
</ScrollViewer>
C#
public Constructor()
{
this.InitializeComponent()
InputPane.GetForCurrentView().Showing += Keyboard_OnShow;
InputPane.GetForCurrentView().Hiding += Keyboard_OnHide;
}
private void Keyboard_OnShow(InputPane sender, InputPaneVisibilityEventArgs args)
{
this.scrllvwrKBScroll.Height = this.ActualHeight - args.OccludedRect.Height - 50;
}
private void Keyboard_OnHide(InputPane sender, InputPaneVisibilityEventArgs args)
{
this.scrllvwrKBScroll.height = this.ActualHeight;
}
可能有一种更好的方法可以根据您使用的容器的高度调整高度,但这是我用来让我的应用程序工作的方法。
每当具有BottomAppBar
的Page
在布局中从根视觉对象中移位时,我也会遇到此问题。 这可能是由包装器元素上的Margin
或Padding
引起的。
损坏的可视化树:
-
Window.Current.Content
Frame
-
Border
1pxMargin
-
ContentPresenter
-
Page
BottomAppBar
-
-
-
我找不到"不恶心"的解决方法,但直接在根ScrollViewer
上调整偏移量确实对我有用。 请参阅 UWPMobileScrollIssue 了解完整的重现和解决方法。
// ...snip...
namespace UWPFocusTestApp
{
sealed partial class App : Application
{
// ...snip...
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// ...snip...
if (rootFrame == null)
{
// ...snip...
// Place the frame in the current Window
Window.Current.Content = rootFrame;
#region WORKAROUND
if (AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Mobile")
{
InputPane.GetForCurrentView().Showing += InputPane_Showing;
}
#endregion
}
// ...snip...
}
#region WORKAROUND
private void InputPane_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
// we only need to hook once
InputPane.GetForCurrentView().Showing -= InputPane_Showing;
var frame = (Frame)Window.Current.Content;
// Find root ScrollViewer
DependencyObject cNode = frame;
while (true)
{
var parent = VisualTreeHelper.GetParent(cNode);
if (parent == null)
{
break;
}
cNode = parent;
}
var rootScrollViewer = (ScrollViewer)cNode;
// Hook ViewChanged to update scroll offset
bool hasBeenAdjusted = false;
rootScrollViewer.ViewChanged += (_1, svargs) =>
{
// once the scroll is removed, clear flag
if (rootScrollViewer.VerticalOffset == 0)
{
hasBeenAdjusted = false;
return;
}
// if we've already adjusted, bail.
else if (hasBeenAdjusted)
{
return;
}
var appBar = ((Page)frame.Content)?.BottomAppBar;
if (appBar == null)
{
return;
}
hasBeenAdjusted = true;
rootScrollViewer.ChangeView(null, rootScrollViewer.VerticalOffset + appBar.ActualHeight, null);
};
}
#endregion
// ...snip...
}
}