2015-07-01 9 views

Antwort

17

Der Weg, um dies zu beheben, ist mit einem benutzerdefinierten Renderer, der auf die Tastatur hört und fügt Polsterung, während es da ist.

In Ihrem PCL Projekt KeyboardResizingAwareContentPage.cs:

using Xamarin.Forms; 

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

In Ihrem iOS-Projekt, 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); 
      } 
     } 
    } 
} 
+0

Das Ergebnis ist gut, aber wie kann ich tun, um die Tastatur zu verstecken? Denn wenn ich draußen tippe, schließt sich die Tastatur nicht ... –

+0

@ Fran_gg7 benutze ResignFirstResponder(). Also "Ihr Steuerelement, das die Tastatur aktiviert" ResignFirstResponder(); – Sturla

+0

Xamarin Forms sollte auf der Seite einen Gestenerkenner haben, der automatisch 'ResignFirstResponder' für Sie aufruft. Manchmal möchten Sie dieses Verhalten nicht, für das der 'Bancel'CancelSTouchesInView' ist; Setzen Sie es auf "false", um das Standardverhalten von Xamarin Forms abzubrechen. –

2

Diese Xamarin Forum question diskutiert sich.

Außerdem, wenn Sie es in Android wollen Xamarin/Formulare verwenden Sie diese in Ihre Haupttätigkeit nur einstellen:

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

fand ich, dass die KeyboardOverlap plugin funktioniert besser als die Lösung von Anthony. Diese

ist, wie ich es verwenden:

  1. ein Renderer individuelle Erstellen
public class KeyboardResizingAwareContentPage : ContentPage 
{ 
} 
  1. den benutzerdefinierten Renderer auf iOS implementieren. Hier ist der wichtige Teil der paulpatarinski Code:
[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; 
    } 
} 

Und die fehlenden Erweiterungen:

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. Verwenden Sie die benutzerdefinierte Seiten Renderer
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> 

Alle Credits dafür gehen an Paul! Danke dafür!

+0

Auch diese Lösung wird ausgelöst (aus Produktionsprotokollen): System.ObjectDisposedException: Zugriff auf ein entsorgtes Objekt nicht möglich.Objektname: 'IosKeyboardFixPageRenderer'. –

+0

_isKeyboardShown = false; sollte am Ende der Methode UnregisterForKeyboardNotifications verschoben werden –

Verwandte Themen