Answers:
通常的解决方案是使用动画将字段(及其上方的所有内容)向上滑动,然后在完成后向下滑动。您可能需要将文本字段和其他一些项目放入另一个视图,然后将视图作为一个单元滑动。(我把这些东西称为“板块”,就像“构造板块”一样,但这就是我)。但是,如果您不需要花哨的话,这是一个基本思路。
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 80; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
这为我滑动uitextfields创造了奇迹
特别地,它具有根据文本字段的位置计算幻灯片动画距离的好处。
IQKeyboardManager无需使用代码行即可为您完成此操作,只需要将相关的源文件拖放到项目中即可。IQKeyboardManager还支持设备方向,自动UIToolbar管理,keyboardDistanceFromTextField等,远远超出您的想象。
这是控制流程图:
第一步: -增加了全球的通知UITextField
,UITextView
和UIKeyboard
在一个单独的类。我称它为IQKeyboardManager。
第二步: -如果找到UIKeyboardWillShowNotification
,UITextFieldTextDidBeginEditingNotification
或UITextViewTextDidBeginEditingNotification
通知,然后尝试获得topMostViewController
从实例UIWindow.rootViewController
层次结构。为了正确地发现UITextField
/ UITextView
,topMostViewController.view
需要调整的框架。
步骤3:-计算topMostViewController.view
相对于第一响应UITextField
/的预期移动距离UITextView
。
第四步: -感动topMostViewController.view.frame
向上/根据预期的移动距离了。
第五步: -如果找到UIKeyboardWillHideNotification
,UITextFieldTextDidEndEditingNotification
或UITextViewTextDidEndEditingNotification
通知,然后再次尝试获得topMostViewController
从实例UIWindow.rootViewController
层次结构。
步骤6:-计算出的受干扰距离topMostViewController.view
需要恢复到其原始位置。
步骤7:-已还原topMostViewController.view.frame
根据受干扰的距离。
步骤8:-在应用加载时实例化了单例IQKeyboardManager类实例,因此每个UITextField
/UITextView
将根据预期的移动距离自动进行调整。
就这样
为了扩展关于Amagrammer的答案,这里是一个示例类:
LoginViewController.h
@interface LoginViewController : UIViewController <UITextFieldDelegate> {
}
@property (nonatomic, retain) IBOutlet UITextField *emailTextField;
@property (nonatomic, retain) IBOutlet UITextField *passwordTextField;
注意我们正在实现“ UITextFieldDelegate”
LoginViewController.m
@implementation LoginViewController
@synthesize emailTextField=_emailTextField;
@synthesize passwordTextField=_passwordTextField;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
//Register to receive an update when the app goes into the backround
//It will call our "appEnteredBackground method
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appEnteredBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
}
return self;
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 80; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
//This is called when the app goes into the background.
//We must reset the responder because animations will not be saved
- (void)appEnteredBackground{
[self.emailTextField resignFirstResponder];
[self.passwordTextField resignFirstResponder];
}
UIApplicationDidEnterBackgroundNotification
,否则如果再按一次“主页”按钮,它将再次向下移动,再次进入应用程序,从而使其变得丑陋且有故障。
官方解决方案如何: 移动位于键盘下方的内容
调整内容通常涉及临时调整一个或多个视图的大小并对其进行定位,以使文本对象保持可见。用键盘管理文本对象的最简单方法是将它们嵌入UIScrollView对象(或其子类之一,如UITableView)中。显示键盘时,您要做的就是重置滚动视图的内容区域并将所需的文本对象滚动到适当的位置。因此,响应UIKeyboardDidShowNotification,您的处理程序方法将执行以下操作:
- 获取键盘的大小。
- 通过键盘高度调整滚动视图的底部内容插图。
- 将目标文本字段滚动到视图中。
// 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 app might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
我在UITableView
textField单元格中遇到了同样的问题。我通过实现以下方法来监听键盘通知来解决此问题。
观察者在这里的通知:
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
使用以下功能处理这些通知:
(void)keyboardWasShown:(NSNotification*)aNotification
(void)keyboardWillBeHidden:(NSNotification*)aNotification
看一下这个。不用为您烦恼。
这个解决方案非常简洁。您要做的就是在情节提要中将文本字段添加UIScrollView
到中TPKeyboardAvoidingScollView
,并将其类更改为。滚动视图以这样一种方式扩展:它可以检测何时可见键盘,并将其自身移动到键盘上方合理的距离。这是一个完美的解决方案,因为它独立于您的产品UIViewController
。每个必要的事情都在上述类中完成。谢谢迈克尔·泰森等。
以下是Amagrammer答案的快速版本。另外,使用UIKeyboardWillShowNotification事件的一种变体,因为在移开视图之前,我需要知道键盘的大小。
var keyboardHeight:CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChange:", name: UIKeyboardWillShowNotification, object: nil)
}
func textFieldDidBeginEditing(textField: UITextField) {
//keyboardWillChange (below) is used instead of textFieldDidBeginEditing because textFieldDidBeginEditing
//is called before the UIKeyboardWillShowNotification necessary to determine the keyboard height.
}
func textFieldDidEndEditing(textField: UITextField) {
animateTextField(false)
}
func animateTextField(textFieldUp:Bool) {
let movementDistance:CGFloat = keyboardHeight
let movementDuration = 0.3
let movement:CGFloat = (textFieldUp ? -movementDistance : movementDistance)
UIView.beginAnimations("anim", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
func keyboardWillChange(notification:NSNotification) {
let keyboardRect:CGRect = ((notification.userInfo![UIKeyboardFrameEndUserInfoKey])?.CGRectValue)!
keyboardHeight = keyboardRect.height
animateTextField(true)
}
在编辑文本字段时没有混淆,这是一个很棒的演练(链接现已消失,这是一个Wayback链接:https ://web.archive.org/web/20091123074029/http: //acts-as-geek.blogspot.com/2009/ 11 / editing-textfields-without-obscuring.html)。它显示了如何将现有的移动UIView
到UIScrollView
,并在出现键盘时自动滚动。
我已经对其进行了一些更新,以计算下方UIScrollView
有控件(例如UITabBar
)的正确高度UIScrollBar
。请参阅更新uiview后。
这是使用Xcode5,iOS7的解决方案:
使用UITextfieldDelegate和动画块。
这几乎是ViewController的所有代码,但我想为那些仍不熟悉委托模式(例如我)的人提供委托代码。当您从textview中移开时,我还提供了隐藏键盘的代码。
您可以将视图(按钮,文本字段等)移动到想要的高度,只需确保将它们放回原位(+100,然后再加上-100)。
@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *MyTextField;
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.MyTextField.delegate = self;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(@"text began editing");
CGPoint MyPoint = self.MyTextField.center;
[UIView animateWithDuration:0.3
animations:^{
self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y - 100);
}];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSLog(@"text ENDED editing");
CGPoint MyPoint = self.MyTextField.center;
[UIView animateWithDuration:0.3
animations:^{
self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y + 100);
}];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
我猜一种方法是单击文本字段时将整个视图位置从(x,y)移到(x,y-keybaardHeight),然后在关闭键盘时放回原处,可能看起来有点奇怪出现(如果设置动画,可能不会很坏)。
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect frame=self.view.frame;
frame.origin=CGPointMake(x...//set point here
self.view.frame=frame;
}
除了Amagrammer的解决方案之外,如果您在纵向模式下使用cocos2d,请更改以下行:
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
对此:
[CCDirector sharedDirector].openGLView.frame = CGRectOffset([CCDirector sharedDirector].openGLView.frame, movement, 0);
如果您在横向模式下使用cocos2d,请进行上述更改并up
在textFieldDidBeginEditing:
和中切换值textFieldDidEndEditing:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[self animateTextField:textField up:NO];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
[self animateTextField:textField up:YES];
}
我遇到了同样的问题,发现GTKeyboardHelper是一个简单的解决方法。
将框架拖放到项目中后,包括头文件。下载并打开示例项目,然后将“键盘帮助器”对象从xib的对象部分拖到项目的界面构建器中的对象部分。
拖放所有视图,使其成为“键盘帮助器”的子视图。
我在项目中使用的拖放框架。当您点击急救人员之外或滚动时,支持自动解雇。
只需根据需要上下滑动视图:
- (void)textFieldDidEndEditing:(UITextField *)textField {
self.currentTextField = nil;
[self animateTextField: textField up: NO];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.currentTextField resignFirstResponder];
return YES;
}
- (void) animateTextField:(UITextField*) textField up:(BOOL)up {
const int movementDistance = 80; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView animateWithDuration:movementDuration animations:^{
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
}];
}
不要忘记将和设置self
为UITextFieldDelegate
实际的textField delegate
。
(感谢Ammagrammer,这是使用动画块的简短答案)
如果您愿意,我还有别的东西。这里的要点是您要在编辑的文本字段上将UIView设置为中心。
在此之前,你必须保存INITIAL_CENTER,作为一个CGPoint,从self.view.center和你INITIAL_VIEW作为的CGRect在一个const财产self.view.frame。
您可以创建这样的方法:
- (void) centerOn: (CGRect) fieldFrame {
// Set up the center by taking the original view center
CGPoint center = CGPointMake(INITIAL_CENTER.x,
INITIAL_CENTER.y - ((fieldFrame.origin.y + fieldFrame.size.height/2) - INITIAL_CENTER.y));
[UIView beginAnimations:@"centerViewOnField" context:nil];
[UIView setAnimationDuration:0.50];
if (CGRectEqualToRect(fieldFrame,INITIAL_VIEW)) {
self.view.frame = INITIAL_VIEW;
[self.view setCenter:INITIAL_CENTER];
} else {
[self.view setCenter:center];
}
[UIView commitAnimations];
}
然后,在UITextFieldDelegate上,必须通过以下方法调用centerOn:(CGRect):
textFieldDidBeginEditing:(UITextField *)以您要居中的文本字段框架为参数。
而且您必须在事件处理程序中调用它,然后关闭键盘,
textFieldDidEndEditing:(UITextField *)可以是执行此操作的方法之一,将INITIAL_VIEW设置为centerOn:(CGRect)的参数。
我相信在更新版本的iOS(6.1或更高版本)上,至少对于UITableView,底层视图会在键盘弹出时自动缩小。因此,您只需要使文本字段在该视图中可见即可。在init
:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
然后:
- (void)keyboardWasShown:(NSNotification*)notification
{
// Scroll the text field into view so it's not under the keyboard.
CGRect rect = [self.tableView convertRect:inputView.bounds fromView:inputView];
[self.tableView scrollRectToVisible:rect animated:YES];
}
https://github.com/ZulwiyozaPutra/Shift-Keyboard-Example我希望该解决方案能有所帮助。它们都是Swift 3编写的。
//
// ViewController.swift
// Shift Keyboard Example
//
// Created by Zulwiyoza Putra on 11/23/16.
// Copyright © 2016 Zulwiyoza Putra. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
//connecting textfield from storyboard
@IBOutlet weak var textField: UITextField!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
subscribeToKeyboardNotifications()
}
override func viewDidAppear(_ animated: Bool) {
self.textField.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
unsubscribeFromKeyboardNotifications()
}
//Hide keyboard after finished editing
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
//Setup view before keyboard appeared
func keyboardWillAppear(_ notification:Notification) {
view.frame.origin.y = 0 - getKeyboardHeight(notification)
}
//Setup view before keyboard disappeared
func keyboardWillDisappear(_ notification: Notification) {
view.frame.origin.y = 0
}
//Getting keyboard height
func getKeyboardHeight(_ notification:Notification) -> CGFloat {
let userInfo = notification.userInfo
let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue // of CGRect
return keyboardSize.cgRectValue.height
}
//Subscribing to notifications to execute functions
func subscribeToKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(_:)), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: .UIKeyboardWillHide, object: nil)
}
//Unsubscribing from notifications
func unsubscribeFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
}