0
votes

I am on the most current version of Xamarin Forms. I have a Carousel Page with a Content Page. The Content Page has a scrollview that has a stacklayout that contains some labels and Entry inputs. When I touch the Entry to enter text, the keyboard covers the entry box so I cannot see what I am typing.

I have tested this functionality on a basic app using just a Content Page (no Carousel) with 8 labels and 8 entries and the Entry box scrolls up (to stay in view) when the keyboard is shown as I would expect it to.

However, when I use a Carousel Page that adds the above Content Page as a child, the keyboard then covers my Entry field.

So, the below works:

    public App()
    {
        InitializeComponent();

        MainPage = new MainPage1();
    }


namespace App2
{

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MainPage1 : ContentPage
    {
        public MainPage1()
        {
            InitializeComponent();

            var vScrollView = new ScrollView
            {
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.FillAndExpand,
                Margin = new Thickness(0, 5, 15, 25),

            };
            var vStackLayout = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                Spacing = 10,
                HorizontalOptions = LayoutOptions.Start,
                VerticalOptions = LayoutOptions.Start,
                Margin = new Thickness(15, 0, 15, 25),
                WidthRequest = 700
            };

            //Create the form label for the item
            var lblItemLabel = new Label
            {
                Text = "Label 1",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel);

            var entry = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry);

            var lblItemLabel2 = new Label
            {
                Text = "Label 2",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel2);

            var entry2 = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry2);

            var lblItemLabel3 = new Label
            {
                Text = "Label 3",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel3);

            var entry3 = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry3);

            var lblItemLabel4 = new Label
            {
                Text = "Label 4",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel4);

            var entry4 = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry4);

            var lblItemLabel5 = new Label
            {
                Text = "Label 5",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel5);

            var entry5 = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry5);

            var lblItemLabel6 = new Label
            {
                Text = "Label 6",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel6);

            var entry6 = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry6);

            var lblItemLabel7 = new Label
            {
                Text = "Label 7",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel7);

            var entry7 = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry7);

            var lblItemLabel8 = new Label
            {
                Text = "Label 8",
                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                Margin = new Thickness(10, 0, 0, 0),
            };
            vStackLayout.Children.Add(lblItemLabel8);

            var entry8 = new Entry
            {
                //HorizontalOptions = LayoutOptions.Fill,
                MinimumWidthRequest = 300,
                Margin = new Thickness(20, 0, 15, 15),
            };
            vStackLayout.Children.Add(entry8);


            vScrollView.Content = vStackLayout;
            Content = vScrollView;
        }
    }

}

However, when I create a CarouselPage and add the above Content Page to it as a child, the keyboard no longer pushes the view up. Instead it covers the Entry field.

The below, does not work:

public App()
{
    InitializeComponent();

    MainPage = new CarouselPage1();
}

namespace App2
{

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class CarouselPage1 : CarouselPage
    {
        public CarouselPage1()
        {
            InitializeComponent();

            var page = new MainPage1(); //Same exact MainPage1 as in first code block above.
            this.Children.Add(page);
        }
    }
}

How do I make the keyboard work properly by not covering my Entry fields when using a CarouselPage?

1
Anyone? It doesn't recognize any change in the page at all when the keyboard appears (that I can tell). I was going to try to use the Page.Height change method or the Page.LayoutChange method but neither of these recognize any changes when the keyboard appears. Anyone have any ideas how I could code a work-around? I need to hit both Windows and iOS. - Stacy

1 Answers

0
votes

I want to give great thanks to Kym Phillpotts @ Microsoft (Xamarin University) for his assistance and solution to this problem. Thanks to my Xamarin University subscription, I was able to use a 1:1 class time with Kym to review this issue and he ultimately provided me with the below code as the fix.

The fix works for both UWP and WinPhone 8.1 (iOS did not have the bug). Kym used Xamarin Effects to capture the keyboard Showing & Hiding events and registered the effect to the scroll view element.

In my PCL, I created a class and placed the below code from Kym:

using Xamarin.Forms;

namespace App2
{
    public class KeyboardSpacingEffect : RoutingEffect
    {
        public KeyboardSpacingEffect() : base("Xamarin.KeyboardSpacingEffect")
        {
        }
    }
}

Then in the UWP and WinPhone platform specific projects, I created a class and placed this code from Kym:

using App2.WinPhone; //Make sure this using statement correctly points to the platform specific project and not the PCL project or you will get an error.
using System.Diagnostics;
using Windows.UI.ViewManagement;
using Xamarin.Forms;
using Xamarin.Forms.Platform.WinRT;

[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(KeyboardSpacingEffect), "KeyboardSpacingEffect")]
namespace App2.WinPhone
{
    public class KeyboardSpacingEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            InputPane.GetForCurrentView().Showing += Keyboard_OnShow;
            InputPane.GetForCurrentView().Hiding += Keyboard_OnHide;

        }

        private void Keyboard_OnHide(InputPane sender, InputPaneVisibilityEventArgs args)
        {
            // debug stuff
            Debug.WriteLine("Keyboard hide");
            var x = Element;
            var y = Control;
            var z = Container;
            Debug.WriteLine($"{x} - {y} - {z}");

            // get the scrollview element and remove the margin
            ScrollView scrollView = Element as ScrollView;
            scrollView.Margin = new Thickness(0, 0, 0, 0);
        }

        private void Keyboard_OnShow(InputPane sender, InputPaneVisibilityEventArgs args)
        {
            // debug stuff
            var x = Element;
            var y = Control;
            var z = Container;
            Debug.WriteLine($"{x} - {y} - {z}");

            // get the scrollview element and add some margin to the bottom = size of keyboard
            ScrollView scrollView = Element as ScrollView;
            scrollView.Margin = new Thickness(0, 0, 0, args.OccludedRect.Height + 20);
        }

        protected override void OnDetached()
        {
            InputPane.GetForCurrentView().Showing += Keyboard_OnShow;
            InputPane.GetForCurrentView().Hiding += Keyboard_OnHide;
        }
    }
}