Редактор прокрутки в Xamarin Forms в поле зрения

Используя 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?

Спасибо

// Йохан


person Johan Karlsson    schedule 22.06.2014    source источник


Ответы (6)


Чтобы получить автоматическую прокрутку для редакторов и записей с помощью 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 г.) есть ошибка, не позволяющая полностью работать с редактором (он хорошо работает с записями). Проблема известна и над ней работают.

[ОБНОВЛЕНИЕ 2014-11-20] Проблема устранена и будет доступна в следующем предварительном выпуске XF 1.3.

person Stephane Delcroix    schedule 22.06.2014
comment
Это не сработает, если у вас есть список внутри. Смешивание прокрутки со списком испортит событие перетаскивания - person João Serra; 05.09.2014
comment
как писали @NavySeal и Falko - вставлять прокрутку внутри свитка (не только в формы) - не лучшая практика. Это не сработает для нестандартных клавиатур, таких как эмодзи или сторонних производителей (например, SwiftKey). - person Marek; 16.06.2017

Я только что наткнулся на этот вопрос при написании крошечного приложения для чата, которое в основном содержит прокручиваемый список сообщений, текстовую запись и кнопку отправки:

Проблема с ранее опубликованным решением заключается в том, что вам нужно будет вложить два вида прокрутки, что не рекомендуется Документация Xamarin.Forms. Чтобы клавиатура не скрывала запись, я нашел следующий взлом:

Я добавляю 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.

person Falko    schedule 21.08.2014

Иногда вы не можете поместить свое основное представление в режим прокрутки, в этих случаях вы можете реализовать это, обработав события клавиатуры в проекте 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

person Daniel Roberts    schedule 28.07.2015
comment
Очень красивое решение Даниэль - person Richard Edwards; 25.11.2015
comment
Это отличное решение. Однако он не учитывает наличие аппаратных клавиатур. : - \ - person valdetero; 01.12.2015

Расширяя ответ от @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;
    }
}
person Timothy Lee Russell    schedule 08.01.2015

Будьте осторожны, 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;
};
person Pedro Lima Jesus    schedule 09.06.2016

Использование ScrollView, как упомянуто выше, устраняет проблему в iOS и частично исправляет в Android. Чтобы полностью исправить проблему в android, я нашел еще одно простое и приятное дополнение.

Только в Android я заменяю редактор форм Xamarin на элемент управления TextEdit, специфичный для Android. Итак, в моем конструкторе страницы у меня есть следующий код только для 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
person Waqas    schedule 31.10.2017