如何防止键盘覆盖我的UI而不是调整其大小?

时间:2015-07-01 22:07:33

标签: ios xamarin.forms

在iOS中,当根节点为ScrollView时键盘出现时,Xamarin.Forms会调整屏幕大小。但是当根节点不是ScrollView时,键盘会隐藏UI的一部分。你如何防止这种情况发生?

4 个答案:

答案 0 :(得分:22)

解决这个问题的方法是使用一个自定义渲染器来侦听显示的键盘,并在其中添加填充。

在您的PCL项目中,KeyboardResizingAwareContentPage.cs

using Xamarin.Forms;

public class KeyboardResizingAwareContentPage : ContentPage {
    public bool CancelsTouchesInView = true;
}

在您的iOS项目中,IosKeyboardFixPageRenderer.cs

using Foundation;
using MyProject.iOS.Renderers;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(KeyboardResizingAwareContentPage), typeof(IosKeyboardFixPageRenderer))]

namespace MyProject.iOS.Renderers {
    public class IosKeyboardFixPageRenderer : PageRenderer {
        NSObject observerHideKeyboard;
        NSObject observerShowKeyboard;

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            var cp = Element as KeyboardResizingAwareContentPage;
            if (cp != null && !cp.CancelsTouchesInView) {
                foreach (var g in View.GestureRecognizers) {
                    g.CancelsTouchesInView = false;
                }
            }
        }

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

            observerHideKeyboard = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, OnKeyboardNotification);
            observerShowKeyboard = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification);
        }

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

            NSNotificationCenter.DefaultCenter.RemoveObserver(observerHideKeyboard);
            NSNotificationCenter.DefaultCenter.RemoveObserver(observerShowKeyboard);
        }

        void OnKeyboardNotification(NSNotification notification)
        {
            if (!IsViewLoaded) return;

            var frameBegin = UIKeyboard.FrameBeginFromNotification(notification);
            var frameEnd = UIKeyboard.FrameEndFromNotification(notification);

            var page = Element as ContentPage;
            if (page != null && !(page.Content is ScrollView)) {
                var padding = page.Padding;
                page.Padding = new Thickness(padding.Left, padding.Top, padding.Right, padding.Bottom + frameBegin.Top - frameEnd.Top);
            }
        }
    }
}

答案 1 :(得分:3)

我发现KeyboardOverlap plugin比安东尼的解决方案更有效。

这就是我使用它的方式:

  1. 创建自定义渲染器
  2. public class KeyboardResizingAwareContentPage : ContentPage
    {
    }
    
    1. 在iOS上实施自定义渲染器。以下是paulpatarinski代码的重要部分:
    2. [Preserve (AllMembers = true)]
      public class KeyboardOverlapRenderer : PageRenderer
      {
          NSObject _keyboardShowObserver;
          NSObject _keyboardHideObserver;
          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 = NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillShowNotification, OnKeyboardShow);
              if (_keyboardHideObserver == null)
                  _keyboardHideObserver = NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillHideNotification, OnKeyboardHide);
          }
      
          void UnregisterForKeyboardNotifications ()
          {
              _isKeyboardShown = false;
              if (_keyboardShowObserver != null) {
                  NSNotificationCenter.DefaultCenter.RemoveObserver (_keyboardShowObserver);
                  _keyboardShowObserver.Dispose ();
                  _keyboardShowObserver = null;
              }
      
              if (_keyboardHideObserver != null) {
                  NSNotificationCenter.DefaultCenter.RemoveObserver (_keyboardHideObserver);
                  _keyboardHideObserver.Dispose ();
                  _keyboardHideObserver = null;
              }
          }
      
          protected virtual void OnKeyboardShow (NSNotification notification)
          {
              if (!IsViewLoaded || _isKeyboardShown)
                  return;
      
              _isKeyboardShown = true;
              var activeView = View.FindFirstResponder ();
      
              if (activeView == null)
                  return;
      
              var keyboardFrame = UIKeyboard.FrameEndFromNotification (notification);
              var isOverlapping = activeView.IsKeyboardOverlapping (View, keyboardFrame);
      
              if (!isOverlapping)
                  return;
      
              if (isOverlapping) {
                  _activeViewBottom = activeView.GetViewRelativeBottom (View);
                  ShiftPageUp (keyboardFrame.Height, _activeViewBottom);
              }
          }
      
          private void OnKeyboardHide (NSNotification notification)
          {
              if (!IsViewLoaded)
                  return;
      
              _isKeyboardShown = false;
              var keyboardFrame = UIKeyboard.FrameEndFromNotification (notification);
      
              if (_pageWasShiftedUp) {
                  ShiftPageDown (keyboardFrame.Height, _activeViewBottom);
              }
          }
      
          private void ShiftPageUp (nfloat keyboardHeight, double activeViewBottom)
          {
              var pageFrame = Element.Bounds;
      
              var newY = pageFrame.Y + CalculateShiftByAmount (pageFrame.Height, keyboardHeight, activeViewBottom);
      
              Element.LayoutTo (new Rectangle (pageFrame.X, newY,
                  pageFrame.Width, pageFrame.Height));
      
              _pageWasShiftedUp = true;
          }
      
          private void ShiftPageDown (nfloat keyboardHeight, double activeViewBottom)
          {
              var pageFrame = Element.Bounds;
      
              var newY = pageFrame.Y - CalculateShiftByAmount (pageFrame.Height, keyboardHeight, activeViewBottom);
      
              Element.LayoutTo (new Rectangle (pageFrame.X, newY,
                  pageFrame.Width, pageFrame.Height));
      
              _pageWasShiftedUp = false;
          }
      
          private double CalculateShiftByAmount (double pageHeight, nfloat keyboardHeight, double activeViewBottom)
          {
              return (pageHeight - activeViewBottom) - keyboardHeight;
          }
      }
      

      缺少的扩展名:

      public static class ViewExtensions
      {
          /// <summary>
          /// Find the first responder in the <paramref name="view"/>'s subview hierarchy
          /// </summary>
          /// <param name="view">
          /// A <see cref="UIView"/>
          /// </param>
          /// <returns>
          /// A <see cref="UIView"/> that is the first responder or null if there is no first responder
          /// </returns>
          public static UIView FindFirstResponder (this UIView view)
          {
              if (view.IsFirstResponder) {
                  return view;
              }
              foreach (UIView subView in view.Subviews) {
                  var firstResponder = subView.FindFirstResponder ();
                  if (firstResponder != null)
                      return firstResponder;
              }
              return null;
          }
      
          /// <summary>
          /// Returns the new view Bottom (Y + Height) coordinates relative to the rootView
          /// </summary>
          /// <returns>The view relative bottom.</returns>
          /// <param name="view">View.</param>
          /// <param name="rootView">Root view.</param>
          public static double GetViewRelativeBottom (this UIView view, UIView rootView)
          {
              var viewRelativeCoordinates = rootView.ConvertPointFromView (view.Frame.Location, view);
              var activeViewRoundedY = Math.Round (viewRelativeCoordinates.Y, 2);
      
              return activeViewRoundedY + view.Frame.Height;
          }
      
          /// <summary>
          /// Determines if the UIView is overlapped by the keyboard
          /// </summary>
          /// <returns><c>true</c> if is keyboard overlapping the specified activeView rootView keyboardFrame; otherwise, <c>false</c>.</returns>
          /// <param name="activeView">Active view.</param>
          /// <param name="rootView">Root view.</param>
          /// <param name="keyboardFrame">Keyboard frame.</param>
          public static bool IsKeyboardOverlapping (this UIView activeView, UIView rootView, CGRect keyboardFrame)
          {
              var activeViewBottom = activeView.GetViewRelativeBottom (rootView);
              var pageHeight = rootView.Frame.Height;
              var keyboardHeight = keyboardFrame.Height;
      
              var isOverlapping = activeViewBottom >= (pageHeight - keyboardHeight);
      
              return isOverlapping;
          }
      }
      
      1. 使用自定义页面渲染器
      2. public partial class LoginPage : KeyboardResizingAwareContentPage
        {
            public LoginPage()
            {
                // your content
                // note: you have to use base.Navigation.PushAsync(), base.DisplayAlert(), ...
            }
        }
        
        <?xml version="1.0" encoding="utf-8" ?>
        <renderer:KeyboardResizingAwareContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App.Pages.LoginPage"
             xmlns:renderer="clr-namespace:App.CustomRenderers;assembly=App">
            <!-- your content -->
        </renderer:KeyboardResizingAwareContentPage>
        

        所有这些都归于保罗!谢谢你!

答案 2 :(得分:2)

Xamarin Forum question讨论了它。

此外,如果你想在Android中使用Xamarin / Forms,你可以在主要活动中设置它:

[Activity(WindowSoftInputMode = Android.Views.SoftInput.AdjustResize)]
public class MainActivity
    ...

答案 3 :(得分:0)

对于Android,在MainActivity之后的LoadApplication(new App());中添加以下代码

App.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().
UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);