コードに問題があります。キーボードポップで非表示にする必要があるUIScrollView
を編集しているときに、UITextField
を移動しようとしています。
コードを「スクロールアップ」する方法がわからないので、今メインフレームを移動しています。そのため、少しコードを実行しましたが、うまく機能していますが、UItextfieldを編集し、「戻る」ボタンを押さずに別のUITextField
に切り替えると、メインビューはさらに大きくなります。
以下に示すように、変数size、distance、textFieldRect.Origin.yでNSLog()
を実行しました。 2つのUITextField
を同じ場所(y Origin)に配置し、この特定の 'switch'(リターンを押すことなく)を実行すると、同じ番号が得られますが、最初のUITextField
編集しますが、2番目の編集用ではありません。
これをチェックしてください:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
{
int size;
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
size = textFieldRect.Origin.y + textFieldRect.size.height;
if (change == FALSE)
{
size = size - distance;
}
if (size < PORTRAIT_KEYBOARD_HEIGHT)
{
distance = 0;
}
else if (size > PORTRAIT_KEYBOARD_HEIGHT)
{
distance = size - PORTRAIT_KEYBOARD_HEIGHT + 5; // +5 px for more visibility
}
NSLog(@"Origin %f", textFieldRect.Origin.y);
NSLog(@"size %d", size);
NSLog(@"distance %d", distance);
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y -= distance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
change = FALSE;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
change = TRUE;
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y += distance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
何か案は ?
Appleからの推奨される方法は、contentInset
のUIScrollView
を変更することです。 contentSize
をいじる必要がないため、非常にエレガントなソリューションです。次のコードは Keyboard Programming Guide からコピーされており、この問題の処理方法が説明されています。あなたはそれを見るべきです。
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, activeField.frame.Origin) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height);
[scrollView setContentOffset:scrollPoint animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
Swiftバージョン:
func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}
// Don't forget to unregister when done
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}
@objc func onKeyboardAppear(_ notification: NSNotification) {
let info = notification.userInfo!
let rect: CGRect = info[UIKeyboardFrameBeginUserInfoKey] as! CGRect
let kbSize = rect.size
let insets = UIEdgeInsetsMake(0, 0, kbSize.height, 0)
scrollView.contentInset = insets
scrollView.scrollIndicatorInsets = insets
// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
var aRect = self.view.frame;
aRect.size.height -= kbSize.height;
let activeField: UITextField? = [addressTextView, servicePathTextView, usernameTextView, passwordTextView].first { $0.isFirstResponder }
if let activeField = activeField {
if aRect.contains(activeField.frame.Origin) {
let scrollPoint = CGPoint(x: 0, y: activeField.frame.Origin.y-kbSize.height)
scrollView.setContentOffset(scrollPoint, animated: true)
}
}
}
@objc func onKeyboardDisappear(_ notification: NSNotification) {
scrollView.contentInset = UIEdgeInsets.zero
scrollView.scrollIndicatorInsets = UIEdgeInsets.zero
}
Xcode 7(ベータ6)上のiOS9のSwift 2.0でこれを実装しましたが、ここで問題なく動作します。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
registerKeyboardNotifications()
}
func registerKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func keyboardWillShow(notification: NSNotification) {
let userInfo: NSDictionary = notification.userInfo!
let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size
let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
var viewRect = view.frame
viewRect.size.height -= keyboardSize.height
if CGRectContainsPoint(viewRect, textField.frame.Origin) {
let scrollPoint = CGPointMake(0, textField.frame.Origin.y - keyboardSize.height)
scrollView.setContentOffset(scrollPoint, animated: true)
}
}
func keyboardWillHide(notification: NSNotification) {
scrollView.contentInset = UIEdgeInsetsZero
scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
}
Swift 3用に編集
contentInset
とscrollIndicatorInset
をSwift 3で設定するだけでよいようです。scrolling/ contentOffsetは自動的に行われます。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
registerKeyboardNotifications()
}
func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow(notification:)),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide(notification:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func keyboardWillShow(notification: NSNotification) {
let userInfo: NSDictionary = notification.userInfo! as NSDictionary
let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
let keyboardSize = keyboardInfo.cgRectValue.size
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
func keyboardWillHide(notification: NSNotification) {
scrollView.contentInset = .zero
scrollView.scrollIndicatorInsets = .zero
}
ここでのすべての答えは、景観の可能性について忘れているようです。デバイスを横向きに回転させたときにこれを機能させたい場合は、問題に直面します。
ここでのコツは、ビューは向きを認識していますが、キーボードは認識していないということです。つまり、ランドスケープでは、キーボードの幅は実際にはその高さであり、その逆も同じです。
コンテンツのインセットを変更するアップルの推奨方法を変更し、横向きをサポートするようにするには、次の使用をお勧めします。
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) {
CGSize origKeySize = keyboardSize;
keyboardSize.height = origKeySize.width;
keyboardSize.width = origKeySize.height;
}
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
scroller.contentInset = contentInsets;
scroller.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect rect = scroller.frame;
rect.size.height -= keyboardSize.height;
NSLog(@"Rect Size Height: %f", rect.size.height);
if (!CGRectContainsPoint(rect, activeField.frame.Origin)) {
CGPoint point = CGPointMake(0, activeField.frame.Origin.y - keyboardSize.height);
NSLog(@"Point Height: %f", point.y);
[scroller setContentOffset:point animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
ここで注意すべき部分は次のとおりです。
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) {
CGSize origKeySize = keyboardSize;
keyboardSize.height = origKeySize.width;
keyboardSize.width = origKeySize.height;
}
つまり、デバイスの向きを検出します。横向きの場合、keyboardSize変数の幅と高さの値を「スワップ」して、各向きで正しい値が使用されるようにします。
Swift 4解決策:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
registerKeyboardNotifications()
}
func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow(notification:)),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide(notification:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardWillShow(notification: NSNotification) {
let userInfo: NSDictionary = notification.userInfo! as NSDictionary
let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
let keyboardSize = keyboardInfo.cgRectValue.size
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
@objc func keyboardWillHide(notification: NSNotification) {
scrollView.contentInset = .zero
scrollView.scrollIndicatorInsets = .zero
}
これに関しては、多くのコーディングをする必要はありません。以下のコードのように非常に簡単です。
この画像のようなペン先からUIScrollviewであなたのすべてのテキストファイル:-
YourViewController.h
@interface cntrInquiryViewController : UIViewController<UIScrollViewDelegate,UITextFieldDelegate>
{
IBOutlet UITextField *txtName;
IBOutlet UITextField *txtEmail;
IBOutlet UIScrollView *srcScrollView;
}
@end
nibからIBOutletを接続し、UItextfiledの各デリゲートとNIBからscrollviewデリゲートも接続します
-(void)viewWillAppear:(BOOL)animated
{
srcScrollView.contentSize = CGSizeMake(320, 500);
[super viewWillAppear:YES];
}
-(void)textFieldDidBeginEditing:(FMTextField *)textField
{
[srcScrollView setContentOffset:CGPointMake(0,textField.center.y-140) animated:YES];//you can set your y cordinate as your req also
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
[srcScrollView setContentOffset:CGPointMake(0,0) animated:YES];
return YES;
}
NOTE Text-filedデリゲートが接続されていない場合、どのメソッドも動作しない場合は、すべてのiBOulateおよびデリゲートが正しく接続されていることを確認してください
Appleの推奨事項は、Swift+ iOSでの自動レイアウトでのUIScrollViewの使用(次のリンクに基づいています: link 1 、- リンク2 、 リンク ):
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var t1: UITextField!
@IBOutlet var t2: UITextField!
@IBOutlet var t3: UITextField!
@IBOutlet var t4: UITextField!
@IBOutlet var srcScrollView: UIScrollView!
@IBOutlet var contentView: UIView!
var contentViewCoordinates: CGPoint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
/* Constraints on content view */
let leftConstraint = NSLayoutConstraint(item:self.contentView,
attribute:NSLayoutAttribute.Leading,
relatedBy:NSLayoutRelation.Equal,
toItem:self.view,
attribute:NSLayoutAttribute.Left,
multiplier:1.0,
constant:0)
self.view.addConstraint(leftConstraint)
let rightConstraint = NSLayoutConstraint(item:self.contentView,
attribute:NSLayoutAttribute.Trailing,
relatedBy:NSLayoutRelation.Equal,
toItem:self.view,
attribute:NSLayoutAttribute.Right,
multiplier:1.0,
constant:0)
self.view.addConstraint(rightConstraint)
/* Tap gesture */
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "hideKeyboard")
// prevents the scroll view from swallowing up the touch event of child buttons
tapGesture.cancelsTouchesInView = false
srcScrollView.addGestureRecognizer(tapGesture)
/* Save content view coordinates */
contentViewCoordinates = contentView.frame.Origin
}
func hideKeyboard() {
t1.resignFirstResponder()
t2.resignFirstResponder()
t3.resignFirstResponder()
t4.resignFirstResponder()
}
var activeField: UITextField?
func textFieldDidBeginEditing(textField: UITextField) {
activeField = textField
}
func textFieldDidEndEditing(textField: UITextField) {
activeField = nil
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let center = NSNotificationCenter.defaultCenter()
center.addObserver(self, selector: "keyboardOnScreen:", name: UIKeyboardDidShowNotification, object: nil)
center.addObserver(self, selector: "keyboardOffScreen:", name: UIKeyboardDidHideNotification, object: nil)
}
func keyboardOnScreen(notification: NSNotification){
// Retrieve the size and top margin (inset is the fancy Word used by Apple)
// of the keyboard displayed.
let info: NSDictionary = notification.userInfo!
let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize!.height, 0.0)
srcScrollView.contentInset = contentInsets
srcScrollView.scrollIndicatorInsets = contentInsets
var aRect: CGRect = self.view.frame
aRect.size.height -= kbSize!.height
//you may not need to scroll, see if the active field is already visible
if (CGRectContainsPoint(aRect, activeField!.frame.Origin) == false) {
let scrollPoint:CGPoint = CGPointMake(0.0, activeField!.frame.Origin.y - kbSize!.height)
srcScrollView.setContentOffset(scrollPoint, animated: true)
}
}
// func keyboardOnScreen(aNotification: NSNotification) {
// let info: NSDictionary = aNotification.userInfo!
// let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size
//
// var bkgndRect: CGRect! = activeField?.superview?.frame
//
// bkgndRect.size.height += kbSize!.height
//
// activeField?.superview?.frame = bkgndRect
//
// srcScrollView.setContentOffset(CGPointMake(0.0, activeField!.frame.Origin.y - kbSize!.height), animated: true)
// }
func keyboardOffScreen(notification: NSNotification){
let contentInsets:UIEdgeInsets = UIEdgeInsetsZero
srcScrollView.contentInset = contentInsets
srcScrollView.scrollIndicatorInsets = contentInsets
self.srcScrollView.setContentOffset(CGPointMake(0, -self.view.frame.Origin.y/2), animated: true)
}
}
Appleコードで更新する唯一のものは、スムーズな移行を提供するkeyboardWillBeHidden:メソッドです。
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
[UIView animateWithDuration:0.4 animations:^{
self.scrollView.contentInset = contentInsets;
}];
self.scrollView.scrollIndicatorInsets = contentInsets;
}
これはSwift互換性のある回答です。これは、Navigation Controller内のView Controllerでも機能します-スクロールビューのcontentInset.top
プロパティを変更するためです。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.registerKeyboardNotifications()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.unregisterKeyboardNotifications()
}
func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardDidShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func unregisterKeyboardNotifications() {
NotificationCenter.default.removeObserver(self)
}
func keyboardDidShow(notification: NSNotification) {
let userInfo: NSDictionary = notification.userInfo! as NSDictionary
let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
let keyboardSize = keyboardInfo.cgRectValue.size
// Get the existing contentInset for the scrollView and set the bottom property to be the height of the keyboard
var contentInset = self.scrollView.contentInset
contentInset.bottom = keyboardSize.height
self.scrollView.contentInset = contentInset
self.scrollView.scrollIndicatorInsets = contentInset
}
func keyboardWillHide(notification: NSNotification) {
var contentInset = self.scrollView.contentInset
contentInset.bottom = 0
self.scrollView.contentInset = contentInset
self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero
}
上記の答えは時代遅れであることがわかりました。スクロールするときも完璧ではありません。
これがSwiftバージョンです。
TextFieldの真下にスクロールします。スペアスペースはありません。そして、それは最初の姿のように復元されます。
//add observer
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}
func keyboardDidShow(notification: NSNotification) {
let userInfo: NSDictionary = notification.userInfo!
let keyboardSize = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)!.CGRectValue.size
let difference = keyboardSize.height - (self.view.frame.height - inputTextField.frame.Origin.y - inputTextField.frame.size.height)
if difference > 0 {
var contentInset:UIEdgeInsets = self.scrollView.contentInset
contentInset.bottom = difference
self.scrollView.contentInset = contentInset
let scrollPoint = CGPointMake(0, difference)
self.scrollView.setContentOffset(scrollPoint, animated: true)
}
}
func keyboardDidHide(notification: NSNotification) {
let contentInset:UIEdgeInsets = UIEdgeInsetsZero
self.scrollView.contentInset = contentInset
}
//remove observer
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
Swift 3でこのコードを試してください:
override func viewDidAppear(_ animated: Bool) {
setupViewResizerOnKeyboardShown()
}
func setupViewResizerOnKeyboardShown() {
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardWillShowForResizing),
name: Notification.Name.UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardWillHideForResizing),
name: Notification.Name.UIKeyboardWillHide,
object: nil)
}
func keyboardWillShowForResizing(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let window = self.view.window?.frame {
// We're not just minusing the kb height from the view height because
// the view could already have been resized for the keyboard before
self.view.frame = CGRect(x: self.view.frame.Origin.x,
y: self.view.frame.Origin.y,
width: self.view.frame.width,
height: window.Origin.y + window.height - keyboardSize.height)
} else {
debugPrint("We're showing the keyboard and either the keyboard size or window is nil: panic widely.")
}
}
func keyboardWillHideForResizing(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let viewHeight = self.view.frame.height
self.view.frame = CGRect(x: self.view.frame.Origin.x,
y: self.view.frame.Origin.y,
width: self.view.frame.width,
height: viewHeight) //viewHeight + keyboardSize.height
} else {
debugPrint("We're about to hide the keyboard and the keyboard size is nil. Now is the rapture.")
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
これは私が使ってきたものです。シンプルでうまく機能します。
#pragma mark - Scrolling
-(void)scrollElement:(UIView *)view toPoint:(float)y
{
CGRect theFrame = view.frame;
float orig_y = theFrame.Origin.y;
float diff = y - orig_y;
if (diff < 0)
[self scrollToY:diff];
else
[self scrollToY:0];
}
-(void)scrollToY:(float)y
{
[UIView animateWithDuration:0.3f animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
self.view.transform = CGAffineTransformMakeTranslation(0, y);
}];
}
UITextField
デリゲート呼び出しtextFieldDidBeginEditing:
を使用してビューを上に移動し、キーボードが非表示になったときにビューを通常に戻す通知オブザーバーを追加します。
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
if (self.view.frame.Origin.y == 0)
[self scrollToY:-90.0]; // y can be changed to your liking
}
-(void)keyboardWillHide:(NSNotification*)note
{
[self scrollToY:0];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
Swift 4.2UIToolbarおよびUITabBarの可能な高さを考慮したソリューション。
private func setupKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIControl.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIControl.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWillShow(_ notification: Notification) {
let userInfo: NSDictionary = notification.userInfo! as NSDictionary
let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.size
let tabbarHeight = tabBarController?.tabBar.frame.size.height ?? 0
let toolbarHeight = navigationController?.toolbar.frame.size.height ?? 0
let bottomInset = keyboardSize.height - tabbarHeight - toolbarHeight
scrollView.contentInset.bottom = bottomInset
scrollView.scrollIndicatorInsets.bottom = bottomInset
}
@objc func keyboardWillHide(_ notification: Notification) {
scrollView.contentInset = .zero
scrollView.scrollIndicatorInsets = .zero
}
また、iOS 9未満をターゲットにしている場合は、ある時点でオブザーバーの登録を解除する必要があります(ありがとう Joe )
これはSwiftで改善された最終コードです
//MARK: UITextFieldDelegate
func textFieldDidBeginEditing(textField: UITextField!) { //delegate method
self.textField = textField
}
func textFieldShouldReturn(textField: UITextField!) -> Bool { //delegate method
textField.resignFirstResponder()
return true
}
//MARK: Keyboard handling
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
unregisterKeyboardNotifications()
}
func registerKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}
func unregisterKeyboardNotifications() {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func keyboardDidShow(notification: NSNotification) {
let userInfo: NSDictionary = notification.userInfo!
let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size
let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
var viewRect = self.view.frame
viewRect.size.height -= keyboardSize.height
let relativeFieldFrame: CGRect = textField.convertRect(textField.frame, toView: self.view)
if CGRectContainsPoint(viewRect, relativeFieldFrame.Origin) {
let scrollPoint = CGPointMake(0, relativeFieldFrame.Origin.y - keyboardSize.height)
scrollView.setContentOffset(scrollPoint, animated: true)
}
}
func keyboardWillHide(notification: NSNotification) {
scrollView.contentInset = UIEdgeInsetsZero
scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
}
私はこのようにします。これは多くのコードですが、現在フォーカスされているtextFieldが「使用可能なスペース」の垂直方向の中央にあることを保証します。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSValue *keyBoardEndFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
CGSize keyboardSize = [keyBoardEndFrame CGRectValue].size;
self.keyboardSize = keyboardSize;
[self adjustScrollViewOffsetToCenterTextField:self.currentTextField];
}
- (void)keyboardWillHide:(NSNotification *)notification {
self.keyboardSize = CGSizeZero;
}
- (IBAction)textFieldGotFocus:(UITextField *)sender {
sender.inputAccessoryView = self.keyboardAccessoryView;
self.currentTextField = sender;
[self adjustScrollViewOffsetToCenterTextField:sender];
}
- (void)adjustScrollViewOffsetToCenterTextField:(UITextField *)textField
{
CGRect textFieldFrame = textField.frame;
float keyboardHeight = MIN(self.keyboardSize.width, self.keyboardSize.height);
float visibleScrollViewHeight = self.scrollView.frame.size.height - keyboardHeight;
float offsetInScrollViewCoords = (visibleScrollViewHeight / 2) - (textFieldFrame.size.height / 2);
float scrollViewOffset = textFieldFrame.Origin.y - offsetInScrollViewCoords;
[UIView animateWithDuration:.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x, scrollViewOffset);
}completion:NULL];
}
you'll need these two properties in your @interface...
@property (nonatomic, assign) CGSize keyboardSize;
@property (nonatomic, strong) UITextField *currentTextField;
- (IBAction)textFieldGotFocus:
アクションは、すべてのtextFieldのDidBeginEditing
状態にフックされることに注意してください。
また、キーボード通知からアニメーション期間を取得し、固定値の代わりにスクロールビューアニメーションに使用する方が少し良いでしょうが、私を訴え、これは私にとって十分でした;)
あまり計算したくない場合は、次の拡張子を使用します。
func scrollSubviewToBeVisible(subview: UIView, animated: Bool) {
let visibleFrame = UIEdgeInsetsInsetRect(self.bounds, self.contentInset)
let subviewFrame = subview.convertRect(subview.bounds, toView: self)
if (!CGRectContainsRect(visibleFrame, subviewFrame)) {
self.scrollRectToVisible(subviewFrame, animated: animated)
}
}
また、UITextFieldを常に表示したい場合があります。
func textViewDidChange(textView: UITextView) {
self.scrollView?.scrollSubviewToBeVisible(textView, animated: false)
}
contentOffset
のプロパティUIScrollView
を使用してスクロールできます。たとえば、
CGPoint offset = scrollview.contentOffset;
offset.y -= KEYBOARD_HEIGHT + 5;
scrollview.contentOffset = offset;
アニメーションスクロールを行う方法もあります。
2番目の編集が正しくスクロールされない理由については、編集が開始されるたびに新しいキーボードが表示されると思われるためです。 「キーボード」の表示位置がすでに調整されているかどうかを確認してみてください(また、元に戻す前にキーボードの可視性を確認してください)。
より良い解決策は、キーボード通知をリッスンすることです。例:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
私はそれが今では古い質問であることを知っていますが、他の人を助けるかもしれないと思いました。私が持っていたいくつかのアプリに実装するのが少し簡単なものが欲しかったので、このクラスを作りました。必要に応じてここからダウンロードできます。 https://github.com/sdernley/iOSTextFieldHandler
すべてのUITextFieldsにselfのデリゲートを設定するのと同じくらい簡単です
textfieldname.delegate = self;
そして、これをあなたのscrollViewとsubmitボタンの名前でView Controllerに追加します
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[iOSTextFieldHandler TextboxKeyboardMover:containingScrollView tf:textField btn:btnSubmit];
}
私のソリューションには4つのステップがあります:
-ステップ1:キーボードが表示されたときに関数がリッスンします
- (void)keyboardWasShown:(NSNotification *)notification {
// Get the size of the keyboard.
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//top: 64 for navigation bar, 0 for without navigation
UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, keyboardSize.height, 0);
_scrollView.contentInset = contentInsets;
_scrollView.scrollIndicatorInsets = contentInsets;
}
-ステップ2:キーボードが消えると関数はリッスンします
- (void)keyboardWillHide:(NSNotification *)notification {
//top: 64 for navigatiob bar
UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, 0, 0);
[_editScrollView setContentInset: contentInsets];
[_editScrollView setScrollIndicatorInsets: contentInsets];
}
-ステップ3:これらの機能を通知センターに追加します。
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
-手順4:View Controllerが無効になったときにリッスンを削除する
- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
実際には、これを行うのにUIScrollViewは必要ありません。私はこのコードを使用し、それは私のために機能します:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (textField==_myTextField)
{
[self keyBoardAppeared];
}
return true;
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
if (textField==_myTextField)
{
[self keyBoardDisappeared];
}
}
-(void) keyBoardAppeared
{
CGRect frame = self.view.frame;
[UIView animateWithDuration:0.3
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
self.view.frame = CGRectMake(frame.Origin.x, frame.Origin.y-215, frame.size.width, frame.size.height);
}
completion:^(BOOL finished){
}];
}
-(void) keyBoardDisappeared
{
CGRect frame = self.view.frame;
[UIView animateWithDuration:0.3
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
self.view.frame = CGRectMake(frame.Origin.x, frame.Origin.y+215, frame.size.width, frame.size.height);
}
completion:^(BOOL finished){
}];
}
最も簡単な解決策の1つは、次のプロトコルを使用することです。
protocol ScrollViewKeyboardDelegate: class {
var scrollView: UIScrollView? { get set }
func registerKeyboardNotifications()
func unregisterKeyboardNotifications()
}
extension ScrollViewKeyboardDelegate where Self: UIViewController {
func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(
forName: UIResponder.keyboardWillChangeFrameNotification,
object: nil,
queue: nil) { [weak self] notification in
self?.keyboardWillBeShown(notification)
}
NotificationCenter.default.addObserver(
forName: UIResponder.keyboardWillHideNotification,
object: nil,
queue: nil) { [weak self] notification in
self?.keyboardWillBeHidden(notification)
}
}
func unregisterKeyboardNotifications() {
NotificationCenter.default.removeObserver(
self,
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil
)
NotificationCenter.default.removeObserver(
self,
name: UIResponder.keyboardWillHideNotification,
object: nil
)
}
func keyboardWillBeShown(_ notification: Notification) {
let info = notification.userInfo
let key = (info?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)
let aKeyboardSize = key?.cgRectValue
guard let keyboardSize = aKeyboardSize,
let scrollView = self.scrollView else {
return
}
let bottomInset = keyboardSize.height
scrollView.contentInset.bottom = bottomInset
scrollView.scrollIndicatorInsets.bottom = bottomInset
if let activeField = self.view.firstResponder {
let yPosition = activeField.frame.Origin.y - bottomInset
if yPosition > 0 {
let scrollPoint = CGPoint(x: 0, y: yPosition)
scrollView.setContentOffset(scrollPoint, animated: true)
}
}
}
func keyboardWillBeHidden(_ notification: Notification) {
self.scrollView?.contentInset = .zero
self.scrollView?.scrollIndicatorInsets = .zero
}
}
extension UIView {
var firstResponder: UIView? {
guard !isFirstResponder else { return self }
return subviews.first(where: {$0.firstResponder != nil })
}
}
このプロトコルを使用する場合は、次のようにして、それに準拠し、コントローラーでスクロールビューを割り当てるだけです。
class MyViewController: UIViewController {
@IBOutlet var scrollViewOutlet: UIScrollView?
var scrollView: UIScrollView?
public override func viewDidLoad() {
super.viewDidLoad()
self.scrollView = self.scrollViewOutlet
self.scrollView?.isScrollEnabled = true
self.registerKeyboardNotifications()
}
extension MyViewController: ScrollViewKeyboardDelegate {}
deinit {
self.unregisterKeyboardNotifications()
}
}
以下は、私のソリューションです(5つのステップ)
ステップ1:オブザーバーを追加して、どのUITEXTFIELDまたはUITEXTVIEW ShoudBeginEditing(オブジェクトが初期化またはViewDidLoadであるかをキャッチします。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateActiveField:)
name:@"UPDATE_ACTIVE_FIELD" object:nil];
ステップ2:UITEXTFIELDまたはUITEXTVIEWのOBJECTを使用して..ShouldBeginEditingを行うときに通知を送信します
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView {
[[NSNotificationCenter defaultCenter] postNotificationName:@"UPDATE_ACTIVE_FIELD"
object:textView];
return YES;
}
Step3:(Step1が呼び出す)現在のUITEXTFIELDまたはUITEXTVIEWを割り当てるメソッド
-(void) updateActiveField: (id) sender {
activeField = [sender object];
}
Step4:キーボードオブザーバーUIKeyboardWillShowNotificationを追加します(Step1と同じ場所)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
および方法:
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
_currentEdgeInsets = self.layoutPanel.contentInset; // store current insets to restore them later
self.layoutPanel.contentInset = contentInsets;
self.layoutPanel.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
CGPoint p = [activeField convertPoint:activeField.bounds.Origin toView:window];
if (!CGRectContainsPoint(aRect, p) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y +kbSize.height);
[self.layoutPanel setContentOffset:scrollPoint animated:YES];
self.layoutPanel.scrollEnabled = NO;
}
}
ステップ5:キーボードオブザーバーUIKeyboardWillHideNotificationを追加します(ステップ1と同じ場所)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
および方法:
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
self.layoutPanel.contentInset = _currentEdgeInsets;
self.layoutPanel.scrollIndicatorInsets = _currentEdgeInsets;
self.layoutPanel.scrollEnabled = YES;
}
オブザーバーを削除することを忘れないでください!
Sudheer Palchuriから提供されたこの回答を使用しました https://stackoverflow.com/users/2873919/sudheer-palchurihttps://stackoverflow.com/a/32583809/6193496
ViewDidLoadで、通知を登録します。
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillShow(_:)), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillHide(_:)), name:UIKeyboardWillHideNotification, object: nil)
キーボードが表示されたときに自動スクロールを行うオブザーバーメソッドを追加します。
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func keyboardWillShow(notification:NSNotification){
var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
keyboardFrame = self.view.convertRect(keyboardFrame, fromView: nil)
var contentInset:UIEdgeInsets = self.scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height
self.scrollView.contentInset = contentInset
}
func keyboardWillHide(notification:NSNotification){
var contentInset:UIEdgeInsets = UIEdgeInsetsZero
self.scrollView.contentInset = contentInset
}