summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs')
-rw-r--r--Xamarin.Forms.Platform.iOS/Renderers/KeyboardInsetTracker.cs109
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