Практически каждое приложение требует того, чтобы в нём присутствовало специальное поле, где пользователь сможет вводить свои данные. На мобильном устройстве при выборе поля ввода вызывается экранная клавиатура, и в зависимости от настроек платформы и приложения следствием этого могут быть различные изменения в вашем лейауте.
Страница Xamarin Forms
В качестве отправного пункта здесь представлена элементарная составляющая страницы Xamarin Forms, создающая 3 секции, на каждой из которых присутствует поле ввода. Сэмпл проекта SoftInput доступен, и с ним можно ознакомиться, если хочется посмотреть на завершенный код.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="https://goo.gl/SkKd9T" xmlns:x="https://goo.gl/korsZp" xmlns:local="clr-namespace:SoftInput" x:Class="SoftInput.MainPage"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="50" /> </Grid.RowDefinitions> <StackLayout Grid.Row="0" BackgroundColor="#1E73BE"> <Entry /> </StackLayout> <StackLayout Grid.Row="1" BackgroundColor="#7030A0"> <Entry /> </StackLayout> <StackLayout Grid.Row="2" BackgroundColor="#00B050"> <Entry /> </StackLayout> </Grid> </ContentPage> |
Android
Android будет часто ссылаться на экранную клавиатуру, выступающую в качестве SoftInput. По умолчанию в Xamarin Forms он использует AdjustPan, который перемещает весь экран вверх, чтобы освободить место для клавиатуры. В результате возникает один проблемный побочный эффект в виде того, что верхняя часть экрана становится недоступной, когда показывается клавиатура.
Если же необходимо изменить размер экрана, тогда следует реализовать два фрагмента кода. Сначала в MainActivity указать SoftInputMode для AdjustResize.
1 | Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize); |
Далее, из-за ошибки в Android, которую в нём всё никак не исправят, нам необходимо реализовать обходной путь.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | public class AndroidBug5497WorkaroundForXamarinAndroid { // For more information, see https://code.google.com/p/android/issues/detail?id=5497 // To use this class, simply invoke assistActivity() on an Activity that already has its content view set. // CREDIT TO Joseph Johnson (http://stackoverflow.com/users/341631/joseph-johnson) for publishing the original Android solution on stackoverflow.com public static void assistActivity(Activity activity) { new AndroidBug5497WorkaroundForXamarinAndroid(activity); } private Android.Views.View mChildOfContent; private int usableHeightPrevious; private FrameLayout.LayoutParams frameLayoutParams; private AndroidBug5497WorkaroundForXamarinAndroid(Activity activity) { FrameLayout content = (FrameLayout)activity.FindViewById(Android.Resource.Id.Content); mChildOfContent = content.GetChildAt(0); ViewTreeObserver vto = mChildOfContent.ViewTreeObserver; vto.GlobalLayout += (object sender, EventArgs e) => { possiblyResizeChildOfContent(); }; frameLayoutParams = (FrameLayout.LayoutParams)mChildOfContent.LayoutParameters; } private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != usableHeightPrevious) { int usableHeightSansKeyboard = mChildOfContent.RootView.Height; int heightDifference = usableHeightSansKeyboard - usableHeightNow; frameLayoutParams.Height = usableHeightSansKeyboard - heightDifference; mChildOfContent.RequestLayout(); usableHeightPrevious = usableHeightNow; } } private int computeUsableHeight() { Rect r = new Rect(); mChildOfContent.GetWindowVisibleDisplayFrame(r); if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) { return (r.Bottom - r.Top); } return r.Bottom; } } |
А затем добавить указанное ниже к строке SetSoftInputMode.
1 | AndroidBug5497WorkaroundForXamarinAndroid.assistActivity(this); |
Ландшафтный режим
Однако, в горизонтальной ориентации Android переходит в полноэкранный режим, как показано ниже.
Это можно отключить путем реализации пользовательского средства визуализации для поля ввода с помощью установки флага ImeOptions в NoExtractUi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [assembly: ExportRenderer(typeof(Entry), typeof(EntryRender))] namespace SoftInput.Droid.Render { using Android.Views.InputMethods; using Xamarin.Forms.Platform.Android; public class EntryRender : EntryRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null) Control.ImeOptions = (ImeAction)ImeFlags.NoExtractUi; } } } |
Посредством реализации этого получается примерно то же самое, что и в портретном режиме.
iOS
По умолчанию в iOS всё это делается ещё более легко. По умолчанию здесь будет выдвигаться AdjustPan, но тут можно просматривать весь контент с помощью прокрутки. Тем не менее для работы скроллинга требуется реализовать ScrollView рядом с контентом, прокрутка которого является возможной. Это не имеет никакого эффекта на Android.
1 2 3 | <ScrollView> // Existing controls in here </ScrollView> |
Можно разместить слишком большие элементы управления в ScrollView для гарантии того, что они продолжат оставаться в видимой области.
UWP
UWP относится к экранной клавиатуре, как к Input Pane. По умолчанию UWP использует AdjustPan так же, как и Android, — без возможности прокрутки.
С тем чтобы произвести изменение размера, я объединяю вот этот код в MainPage.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public MainPage() { this.InitializeComponent(); LoadApplication(new SoftInput.App()); _originalHeight = ApplicationView.GetForCurrentView().VisibleBounds.Height; InputPane.GetForCurrentView().Showing += MainPage_Showing; InputPane.GetForCurrentView().Hiding += MainPage_Hiding; } private double _originalHeight; private void MainPage_Hiding(InputPane sender, InputPaneVisibilityEventArgs args) { this.Height = _originalHeight; this.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Stretch; } private void MainPage_Showing(InputPane sender, InputPaneVisibilityEventArgs args) { this.Height = _originalHeight - args.OccludedRect.Height; this.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Top; } |
В результате получается требуемый эффект, но я должен предупредить, что потребуются дополнительные усовершенствования для реализации поддержки функции вращения.
Если кто-то может поделиться своими мыслями и наработками в части операций с экранной клавиатурой, тогда, пожалуйста, сделайте это в комментариях ниже.
Автор: Adam Pedley
Источник: XamarinHelp.com
1 Comment