Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save topgenorth/f27887a5bbfcf8dc165d to your computer and use it in GitHub Desktop.
Save topgenorth/f27887a5bbfcf8dc165d to your computer and use it in GitHub Desktop.
using System;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using System.Drawing;
namespace TwinCoders.Utils
{
public abstract partial class ParentViewController
{
/// <summary>
/// Call this method from constructor, ViewDidLoad or ViewWillAppear to enable keyboard handling in the main partial class
/// </summary>
void InitKeyboardHandling()
{
//Only do this if required
if (HandlesKeyboardNotifications()) {
RegisterForKeyboardNotifications();
}
}
/// <summary>
/// Set this field to any view inside the textfield to center this view instead of the current responder
/// </summary>
protected UIView ViewToCenterOnKeyboardShown;
protected UIScrollView ScrollToCenterOnKeyboardShown;
/// <summary>
/// Override point for subclasses, return true if you want to handle keyboard notifications
/// to center the active responder in the scroll above the keyboard when it appears
/// </summary>
public virtual bool HandlesKeyboardNotifications()
{
return false;
}
NSObject _keyboardShowObserver;
NSObject _keyboardHideObserver;
protected virtual void RegisterForKeyboardNotifications()
{
if (_keyboardShowObserver == null)
_keyboardShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification);
if (_keyboardHideObserver == null)
_keyboardHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, OnKeyboardNotification);
}
protected virtual void UnregisterForKeyboardNotifications()
{
if (_keyboardShowObserver != null)
{
NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardShowObserver);
_keyboardShowObserver.Dispose();
_keyboardShowObserver = null;
}
if (_keyboardHideObserver != null)
{
NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardHideObserver);
_keyboardHideObserver.Dispose();
_keyboardHideObserver = null;
}
}
/// <summary>
/// Gets the UIView that represents the "active" user input control (e.g. textfield, or button under a text field)
/// </summary>
/// <returns>
/// A <see cref="UIView"/>
/// </returns>
protected virtual UIView KeyboardGetActiveView()
{
return View.FindFirstResponder();
}
private void OnKeyboardNotification (NSNotification notification)
{
if (!IsViewLoaded) return;
//Check if the keyboard is becoming visible
var visible = notification.Name == UIKeyboard.WillShowNotification;
//Start an animation, using values from the keyboard
UIView.BeginAnimations ("AnimateForKeyboard");
UIView.SetAnimationBeginsFromCurrentState (true);
UIView.SetAnimationDuration (UIKeyboard.AnimationDurationFromNotification (notification));
UIView.SetAnimationCurve ((UIViewAnimationCurve)UIKeyboard.AnimationCurveFromNotification (notification));
//Pass the notification, calculating keyboard height, etc.
var keyboardFrame = visible
? UIKeyboard.FrameEndFromNotification(notification)
: UIKeyboard.FrameBeginFromNotification(notification);
OnKeyboardChanged (visible, keyboardFrame);
//Commit the animation
UIView.CommitAnimations ();
}
/// <summary>
/// Override this method to apply custom logic when the keyboard is shown/hidden
/// </summary>
/// <param name='visible'>
/// If the keyboard is visible
/// </param>
/// <param name='keyboardFrame'>
/// Frame of the keyboard
/// </param>
protected virtual void OnKeyboardChanged (bool visible, RectangleF keyboardFrame)
{
var activeView = ViewToCenterOnKeyboardShown ?? KeyboardGetActiveView();
if (activeView == null)
return;
var scrollView = ScrollToCenterOnKeyboardShown ??
activeView.FindTopSuperviewOfType(View, typeof(UIScrollView)) as UIScrollView;
if (scrollView == null)
return;
if (!visible)
scrollView.RestoreScrollPosition();
else
scrollView.CenterView(activeView, keyboardFrame);
}
/// <summary>
/// Call it to force dismiss keyboard when background is tapped
/// </summary>
protected void DismissKeyboardOnBackgroundTap()
{
// Add gesture recognizer to hide keyboard
var tap = new UITapGestureRecognizer { CancelsTouchesInView = false };
tap.AddTarget(() => View.EndEditing(true));
tap.ShouldReceiveTouch = (recognizer, touch) =>
!(touch.View is UIControl || touch.View.FindSuperviewOfType(View, typeof(UITableViewCell)) != null);
View.AddGestureRecognizer(tap);
}
}
}
using System;
using MonoTouch.UIKit;
using System.Drawing;
namespace TwinCoders.Utils
{
public static class ScrollExtensions
{
public static void CenterView(this UIScrollView scrollView, UIView viewToCenter, RectangleF keyboardFrame, bool animated = false) {
var scrollFrame = scrollView.Frame;
var adjustedFrame = UIApplication.SharedApplication.KeyWindow.ConvertRectFromView(scrollFrame, scrollView.Superview);
var intersect = RectangleF.Intersect(adjustedFrame, keyboardFrame);
scrollView.CenterView(viewToCenter, IsLandscape() ? intersect.Width : intersect.Height, animated:animated);
}
public static void CenterView(this UIScrollView scrollView, UIView viewToCenter, float keyboardHeight = 0, bool adjustContentInsets = true, bool animated = false)
{
if (adjustContentInsets)
{
var contentInsets = new UIEdgeInsets(0.0f, 0.0f, keyboardHeight, 0.0f);
scrollView.ContentInset = contentInsets;
scrollView.ScrollIndicatorInsets = contentInsets;
}
// Position of the active field relative isnside the scroll view
RectangleF relativeFrame = viewToCenter.Superview.ConvertRectToView(viewToCenter.Frame, scrollView);
var spaceAboveKeyboard = scrollView.Frame.Height - keyboardHeight;
// Move the active field to the center of the available space
var offset = relativeFrame.Y - (spaceAboveKeyboard - viewToCenter.Frame.Height) / 2;
if (scrollView.ContentOffset.Y < offset) {
scrollView.SetContentOffset(new PointF(0, offset), animated);
}
}
public static void RestoreScrollPosition(this UIScrollView scrollView)
{
scrollView.ContentInset = UIEdgeInsets.Zero;
scrollView.ScrollIndicatorInsets = UIEdgeInsets.Zero;
}
public static bool IsLandscape() {
var orientation = UIApplication.SharedApplication.StatusBarOrientation;
bool landscape = orientation == UIInterfaceOrientation.LandscapeLeft
|| orientation == UIInterfaceOrientation.LandscapeRight;
return landscape;
}
}
}
using System;
using MonoTouch.UIKit;
namespace TwinCoders.Utils
{
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>
/// Find the first Superview of the specified type (or descendant of)
/// </summary>
/// <param name="view">
/// A <see cref="UIView"/>
/// </param>
/// <param name="stopAt">
/// A <see cref="UIView"/> that indicates where to stop looking up the superview hierarchy
/// </param>
/// <param name="type">
/// A <see cref="Type"/> to look for, this should be a UIView or descendant type
/// </param>
/// <returns>
/// A <see cref="UIView"/> if it is found, otherwise null
/// </returns>
public static UIView FindSuperviewOfType(this UIView view, UIView stopAt, Type type)
{
if (view.Superview != null)
{
if (type.IsInstanceOfType(view.Superview))
{
return view.Superview;
}
if (view.Superview != stopAt)
return view.Superview.FindSuperviewOfType(stopAt, type);
}
return null;
}
public static UIView FindTopSuperviewOfType(this UIView view, UIView stopAt, Type type)
{
var superview = view.FindSuperviewOfType(stopAt, type);
var topSuperView = superview;
while (superview != null && superview != stopAt)
{
superview = superview.FindSuperviewOfType(stopAt, type);
if (superview != null)
topSuperView = superview;
}
return topSuperView;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment