diff options
Diffstat (limited to 'Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs')
-rw-r--r-- | Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs b/Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs new file mode 100644 index 00000000..d5759947 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs @@ -0,0 +1,109 @@ +using System; +using System.Drawing; +#if __UNIFIED__ +using UIKit; +#else +using MonoTouch.UIKit; +#endif +#if __UNIFIED__ +using RectangleF = CoreGraphics.CGRect; +using SizeF = CoreGraphics.CGSize; +using PointF = CoreGraphics.CGPoint; + +#else +using nfloat=System.Single; +using nint=System.Int32; +using nuint=System.UInt32; +#endif + +namespace Xamarin.Forms.Platform.iOS +{ + internal class KeyboardInsetTracker : IDisposable + { + readonly Func<UIWindow> _fetchWindow; + readonly Action<PointF> _setContentOffset; + readonly Action<UIEdgeInsets> _setInsetAction; + readonly UIView _targetView; + bool _disposed; + + RectangleF _lastKeyboardRect; + + public KeyboardInsetTracker(UIView targetView, Func<UIWindow> fetchWindow, Action<UIEdgeInsets> setInsetAction) : this(targetView, fetchWindow, setInsetAction, null) + { + } + + public KeyboardInsetTracker(UIView targetView, Func<UIWindow> fetchWindow, Action<UIEdgeInsets> setInsetAction, Action<PointF> setContentOffset) + { + _setContentOffset = setContentOffset; + _targetView = targetView; + _fetchWindow = fetchWindow; + _setInsetAction = setInsetAction; + KeyboardObserver.KeyboardWillShow += OnKeyboardShown; + KeyboardObserver.KeyboardWillHide += OnKeyboardHidden; + } + + public void Dispose() + { + if (_disposed) + return; + _disposed = true; + + KeyboardObserver.KeyboardWillShow -= OnKeyboardShown; + KeyboardObserver.KeyboardWillHide -= OnKeyboardHidden; + } + + //This method allows us to update the insets if the Frame changes + internal void UpdateInsets() + { + //being called from LayoutSubviews but keyboard wasn't shown yet + if (_lastKeyboardRect.IsEmpty) + return; + + var window = _fetchWindow(); + // Code left verbose to make its operation more obvious + if (window == null) + { + // we are not currently displayed and can safely ignore this + // most likely this renderer is on a page which is currently not displayed (e.g. in NavController) + return; + } + + var field = _targetView.FindFirstResponder(); + + //the view that is triggering the keyboard is not inside our UITableView? + //if (field == null) + // return; + + var boundsSize = _targetView.Frame.Size; + + //since our keyboard frame is RVC CoordinateSpace, lets convert it to our targetView CoordinateSpace + var rect = _targetView.Superview.ConvertRectFromView(_lastKeyboardRect, null); + //let's see how much does it cover our target view + var overlay = RectangleF.Intersect(rect, _targetView.Frame); + + _setInsetAction(new UIEdgeInsets(0, 0, overlay.Height, 0)); + + if (field is UITextView && _setContentOffset != null) + { + var keyboardTop = boundsSize.Height - overlay.Height; + var fieldPosition = field.ConvertPointToView(field.Frame.Location, _targetView.Superview); + var fieldBottom = fieldPosition.Y + field.Frame.Height; + var offset = fieldBottom - keyboardTop; + if (offset > 0) + _setContentOffset(new PointF(0, offset)); + } + } + + void OnKeyboardHidden(object sender, UIKeyboardEventArgs args) + { + _setInsetAction(new UIEdgeInsets(0, 0, 0, 0)); + _lastKeyboardRect = RectangleF.Empty; + } + + void OnKeyboardShown(object sender, UIKeyboardEventArgs args) + { + _lastKeyboardRect = args.FrameEnd; + UpdateInsets(); + } + } +}
\ No newline at end of file |