如何让键盘覆盖我的用户界面,而不是resize?

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

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

在您的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); } } } } 

我发现KeyboardOverlap插件比Anthony的解决scheme更好。

这是我如何使用它:

  1. 创build一个自定义的渲染器
 public class KeyboardResizingAwareContentPage : ContentPage { } 
  1. 在iOS上实现自定义渲染器。 这是paulpatarinski代码的重要部分:
 [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; } } 

而缺less的扩展:

 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. 使用自定义页面渲染器
 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> 

所有这一切都归功于保罗! 谢谢你!

这Xamarin论坛问题讨论它。

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

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