xcode 出现键盘时如何向上滚动视图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8706129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to scroll view up when keyboard appears?
提问by Henry F
I know that this question has been asked over and over again, but nothing seems to be working for me. Most of the solutions around are pretty out of date, and the rest are incredibly huge blocks of code that are ten times larger then the actual projects coding. I have a few UITextFields lined up vertically, but when the keyboard launches to edit one, it covers up the text field. I was wondering if there is a simple beginner way to scroll the view up, and then back down when the editing starts and ends?
我知道这个问题已经被一遍又一遍地问了,但似乎没有什么对我有用。周围的大多数解决方案都已经过时了,其余的都是令人难以置信的巨大代码块,比实际项目编码大十倍。我有几个 UITextFields 垂直排列,但是当键盘启动编辑一个时,它覆盖了文本字段。我想知道是否有一种简单的初学者方法可以向上滚动视图,然后在编辑开始和结束时向下滚动?
Thank you.
谢谢你。
采纳答案by Peter DeWeese
I have made solutions that work with scroll and non-scroll views using keyboard notification and a detection of the current first responder, but sometimes I use this trivial solution instead: The simple way is to detect the opening keyboard via the text field delegate's textViewDidBeginEditing:
method and to move the entire view up. The easiest way to do this is with something along the lines of changing self.view.bounds.origin.y
to -100 (or whatever). Use the corresponding textViewShouldEndEditing:
method to set it to the opposite, which is 100 in this case. Changing bounds
is a relative procedure. After changing it the frame is moved but the bounds origin is still zero.
我已经制定了使用键盘通知和检测当前第一响应者来处理滚动和非滚动视图的解决方案,但有时我使用这个简单的解决方案:简单的方法是通过文本字段委托的textViewDidBeginEditing:
方法检测打开的键盘和向上移动整个视图。最简单的方法是使用类似更改self.view.bounds.origin.y
为 -100(或其他值)的方法。使用相应的textViewShouldEndEditing:
方法将其设置为相反,在本例中为 100。改变bounds
是一个相对的过程。更改后,框架移动但边界原点仍然为零。
回答by Guillaume
Since I found it, I use TPKeyboardAvoiding - https://github.com/michaeltyson/TPKeyboardAvoiding.
自从我找到它,我使用 TPKeyboardAvoiding - https://github.com/michaeltyson/TPKeyboardAvoiding。
It is working great, and is very easy to setup:
它工作得很好,并且很容易设置:
- Add a
UIScrollView
into your view controller's xib - Set the scroll view's class to
TPKeyboardAvoidingScrollView
(still in the xib, via the identity inspector) - Place all your controls within that scroll view
- 将 a 添加
UIScrollView
到您的视图控制器的 xib - 将滚动视图的类设置为
TPKeyboardAvoidingScrollView
(仍然在 xib 中,通过身份检查器) - 将所有控件放在该滚动视图中
You can also create it programmatically, if you want.
如果需要,您也可以以编程方式创建它。
There is a class for the same need inside a UITableViewController
; it is only needed in case you support a version of iOS below 4.3.
有一个类可以满足相同的需求UITableViewController
;仅当您支持低于 4.3 的 iOS 版本时才需要它。
回答by Niranjan Balkrishna Prajapati
@BenLu and other users who are facing problem of the function are never getting called is because of following reason: As the delegate inbuild function bydefaults return void instead of BOOL this is how it should be as follows:
@BenLu 和其他面临函数问题的用户永远不会被调用是因为以下原因:由于委托 inbuild 函数默认返回 void 而不是 BOOL,它应该是这样的:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frame = self.view.frame;
frame.origin.y = -100;
[self.view setFrame:frame];
[UIView commitAnimations];
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frame = self.view.frame;
frame.origin.y = 100;
[self.view setFrame:frame];
[UIView commitAnimations];
}
回答by U. Ali
I spent sometime on this problem and gathered pieces code to create one final solution. My problem was related to UITableView scrolling and keyboard open/close.
我花了一些时间解决这个问题并收集了一些代码来创建一个最终的解决方案。我的问题与 UITableView 滚动和键盘打开/关闭有关。
You need two partial methods in your cell class:
您的单元格类中需要两个部分方法:
void EditingBegin(UITextField sender)
{
// Height of tallest cell, you can ignore this!
float tableMargin = 70.0f;
float tableHeight = _tableView.Frame.Size.Height;
float keyBoardHeight = KeyboardHeight();
NSIndexPath[] paths = this._tableView.IndexPathsForVisibleRows;
RectangleF rectLast = this._tableView.RectForSection(paths[paths.Length - 1].Section);
RectangleF rectFirst = this._tableView.RectForSection(paths[0].Section);
float lastCellY = rectLast.Y - rectFirst.Y;
if (lastCellY > tableHeight - keyBoardHeight)
{
float diff = lastCellY - (tableHeight - tableMargin - keyBoardHeight);
this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
}
float cellPosition = this._tableView.RectForSection(this._section).Y;
if (cellPosition > tableHeight - keyBoardHeight)
{
if (this._tableView.ContentInset.Bottom == 0.0f)
{
float diff = cellPosition - (tableHeight - tableMargin - keyBoardHeight);
this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
}
else
{
this._tableView.ScrollToRow(NSIndexPath.FromItemSection(0, this._section), UITableViewScrollPosition.Middle, true);
}
}
}
partial void EditingEnd(UITextField sender)
{
UIView.BeginAnimations(null);
UIView.SetAnimationDuration(0.3f);
this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, 0.0f, 0.0f);
UIView.CommitAnimations();
}
and then in your view controller class:
然后在您的视图控制器类中:
public override void WillAnimateRotation(UIInterfaceOrientation toInterfaceOrientation, double duration)
{
base.WillAnimateRotation(toInterfaceOrientation, duration);
float bottom = this.TableView.ContentInset.Bottom;
if (bottom > 0.0f)
{
if (toInterfaceOrientation == UIInterfaceOrientation.Portrait || toInterfaceOrientation == UIInterfaceOrientation.PortraitUpsideDown)
{
bottom = bottom * UIScreen.MainScreen.Bounds.Width / UIScreen.MainScreen.Bounds.Height;
}
else
{
bottom = bottom * UIScreen.MainScreen.Bounds.Height / UIScreen.MainScreen.Bounds.Width;
}
UIEdgeInsets insets = this.TableView.ContentInset;
this.TableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, bottom, 0.0f);
}
}
回答by Sheharyar
If you have a UITableView
or a UIScrollView
it's better to change values for contentOffset
instead of making changes to the frame
.
如果您有 aUITableView
或 a UIScrollView
,最好更改 的值contentOffset
而不是更改frame
.
Working on Peter's Answer, adding this method to your class works nicely:
处理Peter's Answer,将此方法添加到您的类中效果很好:
- (void)textViewDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGPoint offset = self.tableView.contentOffset;
offset.y += 200; // You can change this, but 200 doesn't create any problems
[self.tableView setContentOffset:offset];
[UIView commitAnimations];
}
That's it, no need to add the textViewDidEndEditing
method.
就是这样,不需要添加textViewDidEndEditing
方法。
I shouldn't need to say this, but for this to work your UITextField
or UITextView
must be a delegateof your controller.
我不需要这么说,但是要使您的UITextField
或UITextView
必须是您的控制器的代表才能使之起作用。
回答by Mario Hendricks
Starting with Peter's answer, I developed the following approach in Swift 3.0 under iOS 10.1. I'm doing this for a textView, so I have implemented the UITextViewDelegate functions textViewDidBeginEditing and textViewDidEndEditing where I adjust the view's bounds. As you can see, I set the origin Y value to a small positive number to scroll up and then back to 0 to return to the original position.
从彼得的回答开始,我在 iOS 10.1 下的 Swift 3.0 中开发了以下方法。我正在为 textView 执行此操作,因此我已经实现了 UITextViewDelegate 函数 textViewDidBeginEditing 和 textViewDidEndEditing,我在其中调整了视图的边界。如您所见,我将原点 Y 值设置为一个小的正数以向上滚动,然后返回到 0 以返回到原始位置。
Here is the relevant code from my ViewController. You don't need to animate, but it adds a nice touch.
这是来自我的 ViewController 的相关代码。你不需要动画,但它增加了一个很好的接触。
func textViewDidBeginEditing(_ textView: UITextView)
{
if UIScreen.main.bounds.height < 568 {
UIView.animate(withDuration: 0.75, animations: {
self.view.bounds.origin.y = 60
})
}
}
func textViewDidEndEditing(_ textView: UITextView)
{
if UIScreen.main.bounds.height < 568 {
UIView.animate(withDuration: 0.75, animations: {
self.view.bounds.origin.y = 0
})
}
}
回答by Rakesh
i have a scrollview and 3 text fields in this. I have a simple code from my own application :
我有一个滚动视图和 3 个文本字段。我有一个来自我自己的应用程序的简单代码:
.h file is :
.h 文件是:
#import <UIKit/UIKit.h>
@interface AddContactViewController : UIViewController<UITextFieldDelegate, UIScrollViewDelegate>
@property (nonatomic, retain) NSDictionary *dict_contactDetail;
@property (nonatomic, retain) IBOutlet UILabel *lbl_name;
@property (nonatomic, retain) IBOutlet UITextField *txtField_tel;
@property (nonatomic, retain) IBOutlet UITextField *txtField_address;
@property (nonatomic, retain) IBOutlet UITextField *txtField_email;
@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
@end
.m file :
.m 文件:
#import "AddContactViewController.h"
@interface AddContactViewController ()
@end
@implementation AddContactViewController
@synthesize dict_contactDetail;
@synthesize lbl_name, txtField_tel, txtField_email, txtField_address, scrollView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// NSLog(@"dict_contactDetail : %@", dict_contactDetail);
UIBarButtonItem * rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Add" style:UIBarButtonSystemItemDone target:self action:@selector(addEmergencyContact:)];
self.navigationItem.rightBarButtonItem = rightButton;
lbl_name.text = [NSString stringWithFormat:@"%@ %@", [dict_contactDetail valueForKey:@"fname"], [dict_contactDetail valueForKey:@"lname"]];
txtField_tel.returnKeyType = UIReturnKeyDone;
txtField_email.returnKeyType = UIReturnKeyDone;
txtField_address.returnKeyType = UIReturnKeyDone;
}
-(void)addEmergencyContact:(id)sender
{
scrollView.frame = CGRectMake(0, 0, 320, 460);
}
#pragma mark - text field delegates
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if([textField isEqual:txtField_tel])
{
[scrollView setContentOffset:CGPointMake(0, 70)];
scrollView.frame = CGRectMake(0, 0, 320, 210);
}
if([textField isEqual:txtField_address])
{
[scrollView setContentOffset:CGPointMake(0, 140)];
scrollView.frame = CGRectMake(0, 0, 320, 210);
}
if([textField isEqual:txtField_email])
{
[scrollView setContentOffset:CGPointMake(0, 210)];
scrollView.frame = CGRectMake(0, 0, 320, 210);
}
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
scrollView.frame = CGRectMake(0, 0, 320, 460);
[textField resignFirstResponder];
return YES;
}
@end