11

使用 Xamarin 表单,请考虑下面的 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 的处理方式是什么?

谢谢

//约翰

4

6 回答 6

12

我在编写一个小型聊天应用程序时偶然发现了这个问题,它基本上包含一个可滚动的消息列表、一个文本条目和一个发送按钮:

先前发布的解决方案的问题是您需要嵌套两个滚动视图,这是Xamarin.Forms 文档不推荐的。为了防止键盘隐藏条目,我发现了以下 hack:

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 上。

于 2014-08-21T08:43:54.360 回答
8

要使用 Xamarin.Forms 自动滚动编辑器和条目,通常只需将视图(在本例中为 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 的下一个-pre 版本中提供

于 2014-06-22T18:24:52.467 回答
5

有时您不能将主视图放在滚动视图中,在这种情况下,您可以通过处理 iOS 项目的键盘事件并将它们传递到表单级别来实现这一点。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;

Listviews 必须以不同的方式处理,因为高度是由 Forms 自动调整的,并且使用间隔会导致过度校正。

示例:https ://github.com/naturalistic/raisekeyboard

于 2015-07-28T17:23:12.537 回答
1

扩展 @Falko 的答案,您可以检查 iOS 平台,因为 Android 会按预期本地处理此问题。

我还通过此答案将其添加到页面中以进行快速而肮脏的定位。

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;
    }
}
于 2015-01-08T05:06:33.140 回答
0

如上所述使用 ScrollView 修复了 iOS 中的问题并部分修复了 Android 中的问题。为了完全解决android中的问题,我发现了另一个简单而漂亮的补充。

仅在 android 中,我将 Xamarin 表单编辑器替换为 android 特定的 TextEdit 控件。因此,在我的 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
于 2017-10-31T10:32:32.563 回答
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;
};
于 2016-06-09T19:05:22.683 回答