使用Xamarin Forms,考虑下面的Xaml。
<StackLayout VerticalOptions="FillAndExpand">
<Image x:Name="cameraImage" Source="camera.png" />
<Label Text="Describe the image" />
<Editor />
<Button Text="Save" />
</StackLayout>
这会渲染图像,编辑器和保存按钮。图像的图像比例为4x3,覆盖了可用屏幕高度的三分之一。编辑器呈现在下面。
问题是键盘覆盖了iOS中的编辑器。通常是标准的iOS问题。
问题是:Xamarin Forms处理此问题的方式是什么?
由于
// Johan
答案 0 :(得分:10)
我在编写一个小聊天应用程序时偶然发现了这个问题,该应用程序基本上包含一个可滚动的消息列表,一个文本条目和一个发送按钮:
之前发布的解决方案存在的问题是您需要嵌套两个滚动视图,Xamarin.Forms documentation不建议这样做。为了防止键盘隐藏条目,我发现了以下黑客:
我在主堆栈布局的末尾添加了placeholder
。根据条目是否被聚焦(即键盘是否可见),占位符的高度设置为0或键盘高度。
// HACK: make entry visible when keyboard open
var placeholder = new BoxView {
HeightRequest = 0,
};
entry.Focused += (sender, e) => placeholder.HeightRequest = 210;
entry.Unfocused += (sender, e) => placeholder.HeightRequest = 0;
Content = new StackLayout {
VerticalOptions = LayoutOptions.Fill,
Padding = 5,
Children = {
whoTable,
messageScrollView,
new StackLayout {
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.End,
HeightRequest = 70,
Children = {
entry,
sendButton,
},
},
placeholder,
},
};
当然,这并不完美。特别是硬编码的键盘高度应该更优雅地实现。也许你应该只在iOS上应用它,而不是在Android上。
答案 1 :(得分:6)
要使用Xamarin.Forms自动滚动编辑器和条目,您通常只需将View(在本例中为StackLayout)打包到ScrollView中:
<ScrollView>
<StackLayout VerticalOptions="FillAndExpand">
<Image x:Name="cameraImage" Source="camera.png" />
<Label Text="Describe the image" />
<Editor />
<Button Text="Save" />
</StackLayout>
</ScrollView>
这就是它应该如何工作,但截至今天(2014年6月),有一个错误阻止它与编辑器完全兼容(它适用于条目)。这个问题已知并正在进行中。
[更新2014-11-20]此问题已得到解决,并将在XF 1.3的下一个预发行版中提供
答案 2 :(得分:5)
有时您无法将主视图放在滚动视图中,在这种情况下,您可以通过处理iOS项目的键盘事件并将其传递到Forms级别来实现此功能。 Android会照顾好自己。
using System;
using Foundation;
using UIKit;
using RaiseKeyboard.iOS;
[assembly: Xamarin.Forms.Dependency (typeof (KeyboardHelper))]
namespace RaiseKeyboard.iOS
{
// Raises keyboard changed events containing the keyboard height and
// whether the keyboard is becoming visible or not
public class KeyboardHelper : IKeyboardHelper
{
public KeyboardHelper() {
NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, OnKeyboardNotification);
NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification);
}
public event EventHandler<KeyboardHelperEventArgs> KeyboardChanged;
private void OnKeyboardNotification (NSNotification notification)
{
var visible = notification.Name == UIKeyboard.WillShowNotification;
var keyboardFrame = visible
? UIKeyboard.FrameEndFromNotification(notification)
: UIKeyboard.FrameBeginFromNotification(notification);
if (KeyboardChanged != null) {
KeyboardChanged (this, new KeyboardHelperEventArgs (visible, (float)keyboardFrame.Height));
}
}
}
}
然后在表格级别:
using System;
using Xamarin.Forms;
namespace RaiseKeyboard
{
// Provides static access to keyboard events
public static class KeyboardHelper
{
private static IKeyboardHelper keyboardHelper = null;
public static void Init() {
if (keyboardHelper == null) {
keyboardHelper = DependencyService.Get<IKeyboardHelper>();
}
}
public static event EventHandler<KeyboardHelperEventArgs> KeyboardChanged {
add {
Init();
keyboardHelper.KeyboardChanged += value;
}
remove {
Init ();
keyboardHelper.KeyboardChanged -= value;
}
}
}
public interface IKeyboardHelper
{
event EventHandler<KeyboardHelperEventArgs> KeyboardChanged;
}
public class KeyboardHelperEventArgs : EventArgs
{
public readonly bool Visible;
public readonly float Height;
public KeyboardHelperEventArgs(bool visible, float height) {
Visible = visible;
Height = height;
}
}
}
如果您正在使用Stacklayout并希望抬起键盘上方的视图,则可以在堆栈底部放置一个高度为0的垫片。然后在引发键盘更改事件时将其设置为键盘的高度。
spacer.HeightRequest = e.Visible ? e.Height : 0;
如果您正在使用Listview,则可以通过将视图转换为重叠的数量来处理此问题。
bottomOffset = mainStack.Bounds.Bottom - textStack.Bounds.Bottom;
textStack.TranslationY -= e.Visible ? e.Height - bottomOffset : bottomOffset - e.Height;
列表视图必须以不同方式处理,因为高度会自动通过表单进行调整,并使用间隔结果进行校正。
答案 3 :(得分:1)
扩展@Falko的答案,您可以检查iOS平台,因为Android本身就按预期处理了这个问题。
我还通过this answer将此页面添加到页面中,以便进行快速而肮脏的定位。
static bool IsPortrait(Page p) { return p.Width < p.Height; }
无论如何,据我所知,Xamarin很快就会为此添加一些解决方案。现在,虽然......
protected async void Message_Focused(object sender, EventArgs args)
{
if (Device.OS == TargetPlatform.iOS)
{
//TLR: still need a way to determine the iOS keyboard's height first
//until then, this is a functional hack
if (IsPortrait(this))
{
KeyboardSpacer.HeightRequest = 165;
}
else
{
KeyboardSpacer.HeightRequest = 114;
}
}
}
protected async void Message_Unfocused(object sender, EventArgs args)
{
if (Device.OS == TargetPlatform.iOS)
{
KeyboardSpacer.HeightRequest = 0;
}
}
答案 4 :(得分:0)
小心,raisekeyboard
刚刚在应用程序中为一个条目实现,如果你添加一个新条目,KeyboardHelper.KeyboardChanged
将要拍摄,当焦点在任何条目中时。
KeyboardHelper.KeyboardChanged += (sender, e) =>{
bottomOffset = this.ParentView.Bounds.Bottom - _editor.Bounds.Bottom;
if (KeyboardStatus)
_editor.TranslationY = e.Visible ? -(e.Height - bottomOffset) : 0;
else
_editor.TranslationY = 0;
};
答案 5 :(得分:0)
如上所述使用ScrollView修复了iOS中的问题并在Android中部分修复了问题。为了完全解决android中的问题,我发现了另一个简单而又不错的补充。
仅在android中我用Android特定的TextEdit控件替换Xamarin表单编辑器。所以在我的Page构造函数中,我有以下代码仅用于android。
#if __ANDROID__
// I have editor defined in xaml named ReportTextEditor in stacklayout named MainStackLayout
Editor sharedEditor = this.ReportTextEditor;
MainStackLayout.Children.Remove(sharedEditor); //removing the ReportTextEditor which was defined in xaml
EditText editText = new EditText(Forms.Context); //created android specific editor
editText.InputType = InputTypes.ClassText | InputTypes.TextFlagAutoCorrect | InputTypes.TextFlagCapSentences | InputTypes.TextFlagMultiLine; //keyboard options, optional
MainStackLayout.Children.Add(editText); //Added android specific edit text to my stack layout
#endif
您还需要根据需要添加特定于Android的命名空间。
#if __ANDROID__
using Xamarin.Forms.Platform.Android;
using Android.Widget;
using Button = Xamarin.Forms.Button;
using Android.Text;
#endif