键盘出现时如何滚动查看?

时间:2012-01-02 22:49:06

标签: iphone xcode keyboard scroll uitextfield

我知道这个问题一再被问到,但似乎没有什么对我有用。大多数解决方案都已过时,其余的是非常庞大的代码块,比实际的项目编码大十倍。我有几个UITextField垂直排列,但当键盘启动编辑一个时,它会覆盖文本字段。我想知道是否有一种简单的初学者方式来滚动视图,然后在编辑开始和结束时退回?

谢谢。

7 个答案:

答案 0 :(得分:29)

我使用键盘通知和当前第一响应者的检测来制作使用滚动和非滚动视图的解决方案,但有时我会使用这个简单的解决方案:简单的方法是通过文本字段检测打开的键盘委托的textViewDidBeginEditing:方法并移动整个视图。最简单的方法是将self.view.bounds.origin.y更改为-100(或其他)。使用相应的textViewShouldEndEditing:方法将其设置为相反的方向,在这种情况下为100。更改bounds是一个相对的过程。更改后,框架会移动,但边界原点仍为零。

答案 1 :(得分:25)

自从我找到它之后,我使用TPKeyboardAvoiding - https://github.com/michaeltyson/TPKeyboardAvoiding

效果很好,设置非常简单:

  • UIScrollView添加到视图控制器的xib
  • 将滚动视图的类设置为TPKeyboardAvoidingScrollView(仍然在xib中,通过身份检查器)
  • 将所有控件放在该滚动视图中

如果需要,您也可以通过编程方式创建它。


UITableViewController内有一个同样需要的类;仅在您支持低于4.3的iOS版本时才需要它。

答案 2 :(得分:3)

@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];
}

答案 3 :(得分:1)

我花了一些时间来解决这个问题并收集了一些代码来创建一个最终的解决方案。我的问题与UITableView滚动和键盘打开/关闭有关。

您的细胞类中需要两个部分方法:

    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();
    }

然后在你的视图控制器类中:

    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);
        }
    }  

答案 4 :(得分:0)

如果您有UITableViewUIScrollView,最好更改contentOffset的值,而不是更改frame

使用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];
}

就是这样,不需要添加textViewDidEndEditing方法。


我不应该这样说,但要实现这一点,您的UITextFieldUITextView 必须是您的控制人的代表

答案 5 :(得分:0)

从彼得的回答开始,我在iOS 10.1下的Swift 3.0中开发了以下方法。我为textView做了这个,所以我实现了UITextViewDelegate函数textViewDidBeginEditing和textViewDidEndEditing,我调整了视图的边界。如您所见,我将原点Y值设置为小的正数以向上滚动然后再返回到0以返回到原始位置。

以下是我的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
        })
    }
}

答案 6 :(得分:-1)

我有一个scrollview和3个文本字段。我有一个来自我自己的应用程序的简单代码:

.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文件:

#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