Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KeyboardOverlap with Editor #109

Open
MichaelRumpler opened this Issue Oct 4, 2016 · 9 comments

Comments

Projects
None yet
7 participants
@MichaelRumpler
Copy link

MichaelRumpler commented Oct 4, 2016

I have an Editor with Height="300" near the top of a page. When the user taps the first row, then the whole Editor is moved up as far as the keyboard is high. Unfortunately the edited text is then not visible anymore.

This can easily be reproduced in the SampleApp if you remove the StackLayout from KeyboardOverlap\SampleApp\SampleApp\Pages\MultiLineText.xaml. Then the Editor occupies the whole page. On my iPad the bottom half of the Editor is empty. When I tap anywhere on the text, then the text is shifted up and I only see the empty lower half of the Editor above the keyboard.

You should make sure, that the cursor always stays visible. If possible, then the height of the UITextView should be changed to be not more than the visible area above the keyboard. That way scrolling within the Editor should still be possible.

@L4rS6

This comment has been minimized.

Copy link

L4rS6 commented Dec 12, 2016

I run into the same problem. Is there any solution available for this problem?

@cd155

This comment has been minimized.

Copy link

cd155 commented Feb 2, 2017

I have the sample problem, hope there is a solution for it.

@phamthanhtong

This comment has been minimized.

Copy link

phamthanhtong commented Mar 23, 2017

me too! :(

@phamthanhtong

This comment has been minimized.

Copy link

phamthanhtong commented Mar 24, 2017

@MichaelRumpler, @cd155 : I fixed it.
In file Path:

KeyboardOverlap/KeyboardOverlap/KeyboardOverlap.Forms.Plugin.iOSUnified/Extensions/ViewExtensions.cs

Change this code:
Before:
var viewRelativeCoordinates = rootView.ConvertPointFromView(view.Frame.Location, view);
After:
var viewRelativeCoordinates = rootView.ConvertPointFromView(view.Bounds.Location, view);
Hope help you!

@cd155

This comment has been minimized.

Copy link

cd155 commented Mar 24, 2017

@phamthanhtong I use nuget package, do you know how i suppose change it with nuget package?

@LuigiMaestrelli

This comment has been minimized.

Copy link

LuigiMaestrelli commented Mar 24, 2017

@phamthanhtong

Did you do anything else?
I have to find a way to limit how much the page will shift up, based on distance between the top of the Editor and the top of the page.

@phamthanhtong

This comment has been minimized.

Copy link

phamthanhtong commented Mar 24, 2017

@TrungNguyen1909

This comment has been minimized.

Copy link

TrungNguyen1909 commented May 30, 2017

@phamthanhtong, when use your patch, it works really good, but if users change the predictive mode while the keyboard is shown, the predictive bar will hide/make space between the keyboard & the entry.
So, I have fixed that issue and here is the additional the code patched:
KeyboardOverlapRenderer.cs

using System;
using Xamarin.Forms.Platform.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
using CoreGraphics;
using KeyboardOverlap.Forms.Plugin.iOSUnified;
using System.Diagnostics;

[assembly: ExportRenderer(typeof(Page), typeof(KeyboardOverlapRenderer))]
namespace KeyboardOverlap.Forms.Plugin.iOSUnified
{
	[Preserve(AllMembers = true)]
	public class KeyboardOverlapRenderer : PageRenderer
	{
		NSObject _keyboardShowObserver;
		NSObject _keyboardHideObserver;
        NSObject _keyboardWillChangeObserver;
		private bool _pageWasShiftedUp;
		private double _activeViewBottom;
		private bool _isKeyboardShown;

		public static void Init()
		{
			var now = DateTime.Now;
			Debug.WriteLine("Keyboard Overlap plugin initialized {0}", now);
		}

		public override void ViewWillAppear(bool animated)
		{
			base.ViewWillAppear(animated);

			var page = Element as ContentPage;

			if (page != null)
			{
				var contentScrollView = page.Content as ScrollView;

				if (contentScrollView != null)
					return;

				RegisterForKeyboardNotifications();
			}
		}

		public override void ViewWillDisappear(bool animated)
		{
			base.ViewWillDisappear(animated);

			UnregisterForKeyboardNotifications();
		}

		void RegisterForKeyboardNotifications()
		{
            if (_keyboardShowObserver == null)
                _keyboardShowObserver = UIKeyboard.Notifications.ObserveWillShow(OnKeyboardShow);
            if (_keyboardHideObserver == null)
                _keyboardHideObserver = UIKeyboard.Notifications.ObserveWillHide(OnKeyboardHide);
            if (_keyboardWillChangeObserver == null)
                _keyboardWillChangeObserver = UIKeyboard.Notifications.ObserveWillChangeFrame(OnKeyboardChangeFrame);
		}


        void UnregisterForKeyboardNotifications()
		{
			_isKeyboardShown = false;
			if (_keyboardShowObserver != null)
			{
				_keyboardShowObserver.Dispose();
				_keyboardShowObserver = null;
			}

			if (_keyboardHideObserver != null)
			{
				_keyboardHideObserver.Dispose();
				_keyboardHideObserver = null;
			}
            if(_keyboardWillChangeObserver!=null)
            {
                _keyboardWillChangeObserver.Dispose();
                _keyboardWillChangeObserver = null;
            }
		}

        private void OnKeyboardShow(object sender,UIKeyboardEventArgs notification)
		{
			if (!IsViewLoaded || _isKeyboardShown)
				return;

			_isKeyboardShown = true;
			var activeView = View.FindFirstResponder();

			if (activeView == null)
				return;

            var keyboardFrame = notification.FrameEnd;
			var isOverlapping = activeView.IsKeyboardOverlapping(View, keyboardFrame);

			if (!isOverlapping)
				return;

			if (isOverlapping)
			{
				_activeViewBottom = activeView.GetViewRelativeBottom(View);
				ShiftPageUp(keyboardFrame.Height, _activeViewBottom);
			}
		}

        private void OnKeyboardHide(object sender, UIKeyboardEventArgs notification)
		{
			if (!IsViewLoaded)
				return;

			_isKeyboardShown = false;
            var keyboardFrame = notification.FrameEnd;

			if (_pageWasShiftedUp)
			{
				var activeView = View.FindFirstResponder();

				if (activeView == null)
					return;
                _activeViewBottom = activeView.GetViewRelativeBottom(View);
				ShiftPageDown(keyboardFrame.Height, _activeViewBottom);
			}
		}
        private void OnKeyboardChangeFrame(object sender, UIKeyboardEventArgs notification)
        {
            var keyboardFrame = notification.FrameEnd;
            if ((_isKeyboardShown) && (!keyboardFrame.Y.Equals(Element.Bounds.Height)))
            {
				if (!IsViewLoaded)
					return;

				var activeView = View.FindFirstResponder();

				if (activeView == null)
					return;
                var isOverlapping = activeView.IsKeyboardOverlapping(View, keyboardFrame);
                if(isOverlapping)
                {
                    _activeViewBottom = activeView.GetViewRelativeBottom(View);
                    if (keyboardFrame.Height > notification.FrameBegin.Height)
                        ShiftPageUp(keyboardFrame.Height - notification.FrameBegin.Height, Element.Bounds.Height, false);
                    else
                        ShiftPageDown(notification.FrameBegin.Height - keyboardFrame.Height, Element.Bounds.Height, false);
                }
			}
            else return;

        }
		private void ShiftPageUp(nfloat keyboardHeight, double activeViewBottom,bool willResetLater=true)
		{
			var pageFrame = Element.Bounds;

			var newY = pageFrame.Y + CalculateShiftByAmount(pageFrame.Height, keyboardHeight, activeViewBottom);

			Element.LayoutTo(new Rectangle(pageFrame.X, newY,
				pageFrame.Width, pageFrame.Height));
            if (willResetLater)
                _pageWasShiftedUp = true;
		}

		private void ShiftPageDown(nfloat keyboardHeight, double activeViewBottom,bool willResetLater=true)
		{
			var pageFrame = Element.Bounds;

			var newY = pageFrame.Y - CalculateShiftByAmount(pageFrame.Height, keyboardHeight, activeViewBottom);

			Element.LayoutTo(new Rectangle(pageFrame.X, newY,
				pageFrame.Width, pageFrame.Height));
            if (willResetLater)
                _pageWasShiftedUp = false;
		}

		private double CalculateShiftByAmount(double pageHeight, nfloat keyboardHeight, double activeViewBottom)
		{
			return (pageHeight - activeViewBottom) - keyboardHeight;
		}
	}
}

@gaffkins

This comment has been minimized.

Copy link

gaffkins commented May 9, 2018

I have this problem when Editor with OnTextChanged has InvalidateMeasure is use in NavigationPage, only NavigationPage.
Here is example Link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.