如何将被键盘遮挡的编辑器滚动到视图中?
How do I scroll an Editor that has been obscured by the keyboard into view?
我正在 Xamarin.Forms 中设计一个 UI 来收集用户对我们应用程序的反馈。此页面底部有一个编辑器控件。在 iPhone 4S 和许多横向模式下,键盘完全遮盖了此编辑器控件。在 Android 上,这不是什么大问题,因为 OS 会自动滚动(尽管调整大小的行为有点奇怪。)在 iOS 上,唯一类似于解决方案的东西非常不稳定。
在原生 iOS 中,解决方案很简单:将您的视图包裹在 UIScrollView 中,然后当键盘出现时,将 space 添加到内容大小并适当滚动. Xamarin 没有暴露任何东西来控制 ScrollView 中的滚动位置,并且 ContentSize 是私有的,所以就这样了。一些 posts (here and here) 似乎表明 ScrollView 至少是解决方案的一部分。看起来 Xamarin 确实有一些自动滚动行为,但它......很好奇。
我的布局相当简单:
- 在顶部,我不想滚动到视图之外的固定导航栏。
- 在此下方,一张 180 像素高的图片代表应用程序的屏幕截图。
- 在其下方,带有时间戳等信息的标签。 (2-3 行文本)。
- 在此之下,编辑器,填补剩余可用space。
我在 post 的底部包含了我尝试过的布局代码。我创建了一个包含图像、标签和编辑器的 StackLayout。我把它放在 ScrollView 中。然后,我创建了一个 RelativeLayout 并将导航栏放在左上角,下面是 ScrollView。
我希望在点击编辑器时发生的事情是显示键盘,如果它遮挡了编辑器,则向上推动布局以使编辑器可见。相反,Xamarin 似乎将布局向上滚动键盘高度加上一些看起来像键盘实用工具栏高度的边距。这将编辑器向上推得如此之高,以至于被导航栏遮住了。
我尝试了很多不同的调整,但我不知所措。我无法控制足够的 ScrollView 来获得我需要的行为。我看到过在编辑器获得焦点时使用 BoxView 调整大小的建议,但要使其真正正常工作,我仍然必须挂钩 iOS 通知以获得适当的大小 和 对我的编辑的界限在哪里有相当深入的了解。感觉不对。
Xamarin.Forms 上还有其他人对此有解决方案吗?就算非要学native,我也想要一个答案。
(这是一个演示问题的示例布局,因为我正在调试,所以结构有点奇怪。时髦的颜色也是布局调试的遗物。)
using System;
using Xamarin.Forms;
namespace TestScroll
{
public class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
}
private ScrollView _scroller;
protected void InitializeComponent() {
var mainLayout = new RelativeLayout();
var navbar = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.White,
Text = "I am the Nav Bar",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.StartAndExpand
};
var subLayout = new ScrollView() {
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
_scroller = subLayout;
var subStack = new StackLayout();
subStack.Spacing = 0;
subLayout.Content = subStack;
var image = new BoxView() {
Color = Color.Green,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Fill,
HeightRequest = 300
};
subStack.Children.Add(image);
var infoLabel = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.Black,
Text = "Timestamp!\r\nOther stuff!",
VerticalOptions = LayoutOptions.Start
};
subStack.Children.Add(infoLabel);
var editor = new Editor() {
VerticalOptions = LayoutOptions.FillAndExpand
};
subStack.Children.Add(editor);
mainLayout.Children.Add(navbar,
Constraint.Constant(0),
Constraint.Constant(20),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.Constant(70));
mainLayout.Children.Add(subLayout,
Constraint.Constant(0),
Constraint.RelativeToView(navbar, (parent, view) => navbar.Bounds.Bottom),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.RelativeToView(navbar, TestConstraint));
Content = mainLayout;
}
private double TestConstraint(RelativeLayout parent, View view) {
double result = parent.Height - view.Bounds.Height;
Console.WriteLine ("Lower stack height : {0}", result);
Console.WriteLine ("Scroll content size: {0}", _scroller.ContentSize);
return result;
}
}
}
我注意到一件事是您将 ScrollView
(subLayout
) 添加到另一个 ScrollView
(_scroller
)。
此外,我 运行 在 iOS 上遇到了同样的问题,只是我的所有控件都在 Grid
内。只需将 Grid
放入单个 ScrollView
即可解决问题,而无需更改内容大小或类似内容。
这个问题搁置了很长时间没有得到解答,这就是我所做的。我不知道它是 'answer',我非常感谢 hvaughan3 目前在这里的回答,如果有时间我会尝试一下。
我的页面在 Android 上表现得就像我想要的那样,所以我没有为此做任何具体的事情。
所以我为 iOS 编写了使用通知 UIKeyboardWillShow
和 UIKeyboardWillHide
的特定代码。这些通知提供有关键盘将占用的边界的信息。因此,当我收到 'show' 通知时,我会操纵我的布局,以便为我放置在键盘下方的那个大小的元素留出空间。当我收到 'hide' 通知时,我重置了布局。
这很糟糕,有点尴尬,我希望能带回消息我尝试了另一种解决方案,如 hvaughan3,但它奏效了。
我正在 Xamarin.Forms 中设计一个 UI 来收集用户对我们应用程序的反馈。此页面底部有一个编辑器控件。在 iPhone 4S 和许多横向模式下,键盘完全遮盖了此编辑器控件。在 Android 上,这不是什么大问题,因为 OS 会自动滚动(尽管调整大小的行为有点奇怪。)在 iOS 上,唯一类似于解决方案的东西非常不稳定。
在原生 iOS 中,解决方案很简单:将您的视图包裹在 UIScrollView 中,然后当键盘出现时,将 space 添加到内容大小并适当滚动. Xamarin 没有暴露任何东西来控制 ScrollView 中的滚动位置,并且 ContentSize 是私有的,所以就这样了。一些 posts (here and here) 似乎表明 ScrollView 至少是解决方案的一部分。看起来 Xamarin 确实有一些自动滚动行为,但它......很好奇。
我的布局相当简单:
- 在顶部,我不想滚动到视图之外的固定导航栏。
- 在此下方,一张 180 像素高的图片代表应用程序的屏幕截图。
- 在其下方,带有时间戳等信息的标签。 (2-3 行文本)。
- 在此之下,编辑器,填补剩余可用space。
我在 post 的底部包含了我尝试过的布局代码。我创建了一个包含图像、标签和编辑器的 StackLayout。我把它放在 ScrollView 中。然后,我创建了一个 RelativeLayout 并将导航栏放在左上角,下面是 ScrollView。
我希望在点击编辑器时发生的事情是显示键盘,如果它遮挡了编辑器,则向上推动布局以使编辑器可见。相反,Xamarin 似乎将布局向上滚动键盘高度加上一些看起来像键盘实用工具栏高度的边距。这将编辑器向上推得如此之高,以至于被导航栏遮住了。
我尝试了很多不同的调整,但我不知所措。我无法控制足够的 ScrollView 来获得我需要的行为。我看到过在编辑器获得焦点时使用 BoxView 调整大小的建议,但要使其真正正常工作,我仍然必须挂钩 iOS 通知以获得适当的大小 和 对我的编辑的界限在哪里有相当深入的了解。感觉不对。
Xamarin.Forms 上还有其他人对此有解决方案吗?就算非要学native,我也想要一个答案。
(这是一个演示问题的示例布局,因为我正在调试,所以结构有点奇怪。时髦的颜色也是布局调试的遗物。)
using System;
using Xamarin.Forms;
namespace TestScroll
{
public class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
}
private ScrollView _scroller;
protected void InitializeComponent() {
var mainLayout = new RelativeLayout();
var navbar = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.White,
Text = "I am the Nav Bar",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.StartAndExpand
};
var subLayout = new ScrollView() {
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
_scroller = subLayout;
var subStack = new StackLayout();
subStack.Spacing = 0;
subLayout.Content = subStack;
var image = new BoxView() {
Color = Color.Green,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Fill,
HeightRequest = 300
};
subStack.Children.Add(image);
var infoLabel = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.Black,
Text = "Timestamp!\r\nOther stuff!",
VerticalOptions = LayoutOptions.Start
};
subStack.Children.Add(infoLabel);
var editor = new Editor() {
VerticalOptions = LayoutOptions.FillAndExpand
};
subStack.Children.Add(editor);
mainLayout.Children.Add(navbar,
Constraint.Constant(0),
Constraint.Constant(20),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.Constant(70));
mainLayout.Children.Add(subLayout,
Constraint.Constant(0),
Constraint.RelativeToView(navbar, (parent, view) => navbar.Bounds.Bottom),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.RelativeToView(navbar, TestConstraint));
Content = mainLayout;
}
private double TestConstraint(RelativeLayout parent, View view) {
double result = parent.Height - view.Bounds.Height;
Console.WriteLine ("Lower stack height : {0}", result);
Console.WriteLine ("Scroll content size: {0}", _scroller.ContentSize);
return result;
}
}
}
我注意到一件事是您将 ScrollView
(subLayout
) 添加到另一个 ScrollView
(_scroller
)。
此外,我 运行 在 iOS 上遇到了同样的问题,只是我的所有控件都在 Grid
内。只需将 Grid
放入单个 ScrollView
即可解决问题,而无需更改内容大小或类似内容。
这个问题搁置了很长时间没有得到解答,这就是我所做的。我不知道它是 'answer',我非常感谢 hvaughan3 目前在这里的回答,如果有时间我会尝试一下。
我的页面在 Android 上表现得就像我想要的那样,所以我没有为此做任何具体的事情。
所以我为 iOS 编写了使用通知 UIKeyboardWillShow
和 UIKeyboardWillHide
的特定代码。这些通知提供有关键盘将占用的边界的信息。因此,当我收到 'show' 通知时,我会操纵我的布局,以便为我放置在键盘下方的那个大小的元素留出空间。当我收到 'hide' 通知时,我重置了布局。
这很糟糕,有点尴尬,我希望能带回消息我尝试了另一种解决方案,如 hvaughan3,但它奏效了。