可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
Thank you.
回答1:
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.
回答2:
Since I found it, I use 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
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.
回答3:
@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:
-(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];
}
回答4:
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.
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);
}
}
回答5:
If you have a UITableView
or a UIScrollView
it's better to change values for contentOffset
instead of making changes to the frame
.
Working on Peter's Answer, adding this method to your class works nicely:
- (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.
I shouldn't need to say this, but for this to work your UITextField
or UITextView
must be a delegate of your controller.
回答6:
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.
Here is the relevant code from my ViewController. You don't need to animate, but it adds a nice touch.
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
})
}
}
回答7:
i have a scrollview and 3 text fields in this. I have a simple code from my own application :
.h file is :
#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 :
#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