Skip to content

Instantly share code, notes, and snippets.

@xleon
Created April 1, 2016 03:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xleon/1fbb7d492472f3c60b263168dca13225 to your computer and use it in GitHub Desktop.
Save xleon/1fbb7d492472f3c60b263168dca13225 to your computer and use it in GitHub Desktop.
Scroll Content when soft keyboard appears/disappears in iOS UIViewController
using System;
using CoreGraphics;
using Foundation;
using HakiOS.Ui.Extensions;
using UIKit;
// adapted from http://forums.xamarin.com/discussion/comment/23235/#Comment_23235
namespace HakiOS.Ui.Utils
{
public class AutoScrollFromKeyboard
{
public UIView ViewToCenterOnKeyboardShown { get; set; }
private UIViewController _controller;
private NSObject _willHideObserver;
private NSObject _willShowObserver;
public AutoScrollFromKeyboard(UIViewController controller,
bool dismissKeyboardOnBackgroundTap = true,
UIView viewToCenterOnKeyboardShown = null)
{
_controller = controller;
ViewToCenterOnKeyboardShown = viewToCenterOnKeyboardShown;
if(dismissKeyboardOnBackgroundTap)
_controller.View.DismissKeyboardOnTap();
RegisterForKeyboardNotifications();
}
private void RegisterForKeyboardNotifications()
{
_willHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, OnKeyboardNotification);
_willShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification);
}
private void OnKeyboardNotification(NSNotification notification)
{
if (!_controller.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 landscape = _controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft
|| _controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeRight;
var keyboardFrame = visible
? UIKeyboard.FrameEndFromNotification(notification)
: UIKeyboard.FrameBeginFromNotification(notification);
OnKeyboardChanged(visible, landscape ? keyboardFrame.Width : keyboardFrame.Height);
//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='keyboardHeight'>
/// Calculated height of the keyboard (width not generally needed here)
/// </param>
protected virtual void OnKeyboardChanged(bool visible, nfloat keyboardHeight)
{
var activeView = ViewToCenterOnKeyboardShown ?? _controller.View.FindFirstResponder();
var scrollView = activeView?.FindSuperviewOfType(_controller.View, typeof(UIScrollView)) as UIScrollView;
if (scrollView == null)
return;
if (!visible)
RestoreScrollPosition(scrollView);
else
CenterViewInScroll(activeView, scrollView, keyboardHeight);
}
protected virtual void CenterViewInScroll(UIView viewToCenter, UIScrollView scrollView, nfloat keyboardHeight)
{
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
var relativeFrame = viewToCenter.Superview.ConvertRectToView(viewToCenter.Frame, scrollView);
var landscape = _controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft
|| _controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeRight;
var spaceAboveKeyboard = (landscape ? scrollView.Frame.Width : scrollView.Frame.Height) - keyboardHeight;
// Move the active field to the center of the available space
var offset = relativeFrame.Y - (spaceAboveKeyboard - viewToCenter.Frame.Height) / 2;
scrollView.ContentOffset = new CGPoint(0, offset);
}
protected virtual void RestoreScrollPosition(UIScrollView scrollView)
{
scrollView.ContentInset = UIEdgeInsets.Zero;
scrollView.ScrollIndicatorInsets = UIEdgeInsets.Zero;
}
public void Dispose()
{
if(_willHideObserver != null)
NSNotificationCenter.DefaultCenter.RemoveObserver(_willHideObserver);
if(_willShowObserver != null)
NSNotificationCenter.DefaultCenter.RemoveObserver(_willShowObserver);
_controller = null;
ViewToCenterOnKeyboardShown = null;
}
}
}
using System;
using System.Linq;
using UIKit;
namespace HakiOS.Ui.Extensions
{
public static class ViewExtensions
{
/// <summary>
/// Will hide soft keyboard when tapping on this view
/// </summary>
public static void DismissKeyboardOnTap(this UIView view)
{
// 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);
view.AddGestureRecognizer(tap);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment