Created
April 1, 2016 03:00
-
-
Save xleon/1fbb7d492472f3c60b263168dca13225 to your computer and use it in GitHub Desktop.
Scroll Content when soft keyboard appears/disappears in iOS UIViewController
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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