在点击键盘上方移动文本字段的逻辑

Posted

技术标签:

【中文标题】在点击键盘上方移动文本字段的逻辑【英文标题】:Logic For Moving Text Field Above Keyboard On Tap 【发布时间】:2012-02-03 20:45:46 【问题描述】:

现在,我有一些基本代码可以在您开始编辑时移动键盘上方的文本字段。但是,文本字段的大小因设备和方向而异。所以,我写了一个粗略的方法,它不会一直保持在键盘上方,而是在你旋转它时会进一步上升,所以它看起来不像我想要的那样专业。

我的问题的基本意义是,是否有一种逻辑可以根据设备和方向获取键盘的大小,并自动使用该值,希望比这更快。

如果这是最好的方法,请告诉我。否则,请提供输入。这是我拥有的代码。 (这里只是上移代码,不是下移代码,以免占用太多空间)

- (void)textFieldDidBeginEditing:(UITextField *)textField  

    //Get Device Type
    NSString *deviceType = [[UIDevice currentDevice] model];

    //Animate Text Field
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDuration:0.4];
    [UIView setAnimationBeginsFromCurrentState:YES];

    if ([deviceType isEqualToString:@"iPhone"]) 

        //Size For iPhone
        googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 210.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);

     else if ([deviceType isEqualToString:@"iPad"]) 

        //Size for iPad
        googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 320.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);

     else if ([deviceType isEqualToString:@"iPod touch"]) 

        //Size For iPod Touch
        googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 210.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);

     

    [UIView commitAnimations];

 

【问题讨论】:

【参考方案1】:

你真正想做的是观察 UIKeyboard(Did|Will)(Show|Hide) 通知。它们在其 userInfo 字典中包含开始和结束帧,以及正确的动画曲线和持续时间。

因此,在观察此通知后,根据提供的动画提示,当它发布时,根据通知中传递的帧的大小移动您的文本字段。

您可以在 UIWindow 类参考的“通知”部分查看更多信息:https://developer.apple.com/library/ios/#documentation/uikit/reference/UIWindow_Class/UIWindowClassReference/UIWindowClassReference.html

下面是一个示例视图控制器实现。这个视图控制器的 nib 只是一个单独的文本字段,它连接了一个插座,并且文本字段的委托设置为视图控制器。

@interface ViewController ()

- (void)viewControllerInit;

@end

@implementation ViewController

@synthesize textField;

- (id)initWithCoder:(NSCoder *)coder 
    self = [super initWithCoder:coder];
    if (self) 
        [self viewControllerInit];
    
    return self;


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
    
        [self viewControllerInit];
    
    return self;



- (void)viewControllerInit

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];



- (void)dealloc 
    [[NSNotificationCenter defaultCenter] removeObserver:self];



#pragma mark - Notification Handlers

- (void)keyboardWillShow:(NSNotification *)notification

    // I'll try to make my text field 20 pixels above the top of the keyboard
    // To do this first we need to find out where the keyboard will be.

    NSValue *keyboardEndFrameValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardEndFrame = [keyboardEndFrameValue CGRectValue];

    // When we move the textField up, we want to match the animation duration and curve that
    // the keyboard displays. So we get those values out now

    NSNumber *animationDurationNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration = [animationDurationNumber doubleValue];

    NSNumber *animationCurveNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
    UIViewAnimationCurve animationCurve = [animationCurveNumber intValue];

    // UIView's block-based animation methods anticipate not a UIVieAnimationCurve but a UIViewAnimationOptions.
    // We shift it according to the docs to get this curve.

    UIViewAnimationOptions animationOptions = animationCurve << 16;


    // Now we set up our animation block.
    [UIView animateWithDuration:animationDuration 
                          delay:0.0 
                        options:animationOptions 
                     animations:^
                         // Now we just animate the text field up an amount according to the keyboard's height,
                         // as we mentioned above.
                        CGRect textFieldFrame = self.textField.frame;
                        textFieldFrame.origin.y = keyboardEndFrame.origin.y - textFieldFrame.size.height - 40; //I don't think the keyboard takes into account the status bar
                        self.textField.frame = textFieldFrame;
                      
                     completion:^(BOOL finished) ];




- (void)keyboardWillHide:(NSNotification *)notification


    NSNumber *animationDurationNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration = [animationDurationNumber doubleValue];

    NSNumber *animationCurveNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
    UIViewAnimationCurve animationCurve = [animationCurveNumber intValue];
    UIViewAnimationOptions animationOptions = animationCurve << 16;

    [UIView animateWithDuration:animationDuration 
                          delay:0.0 
                        options:animationOptions 
                     animations:^
                         self.textField.frame = CGRectMake(20, 409, 280, 31); //just some hard coded value
                      
                     completion:^(BOOL finished) ];


#pragma mark - View lifecycle

- (void)viewDidUnload

    [self setTextField:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;


#pragma mark - UITextFieldDelegate

- (BOOL)textFieldShouldReturn:(UITextField *)textField

    [self.textField resignFirstResponder];
    return YES;


@end

【讨论】:

我可以这样做,我现在正在查看警报部分。但是,您将如何从这些消息中获取实际坐标以便将其实施到我发布的方法中。我现在正在玩弄它,但帮助会很好。 更新:过去 35 分钟我一直在努力。到目前为止,我没有什么可以展示的。你能为我提供一些关于复选标记的帮助吗?非常感谢! 复选标记是什么意思?不过我会发布一些基本代码。 @JTApps 这段代码对您有帮助吗?如果没有,我是否遗漏了您的问题? 这是一个很好的答案。我给了你支票,我现在就去试试。再次感谢!【参考方案2】:

使用通知键盘寄存器,您可以将您的文本字段放在滚动中并管理滚动的内容偏移量,以便在必要时将实际的第一响应者置于键盘上方。

所以在注册控制器到键盘出现后,你必须获取键盘原点和滚动原点相对于父级的距离。

您必须知道特定的第一响应者是否可以更改滚动的内容偏移量,因此有必要知道键盘原点和第一响应者之间可能存在的界限。

顺便说一句,您需要知道滚动内容偏移量和第一响应者之间的差距,以便将您的第一响应者放置在特定位置。

@interface MainViewController : UIViewController

  @property (strong, nonatomic) IBOutlet UIScrollView *scroll;

@end    

@interface MainViewController ()

   CGPoint scrollOffset;

@end 

@implementation MainViewController

@synthesize scroll

-(void)viewWillAppear:(BOOL)animated
 
    [[ NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillAppear:) name:UIKeyboardDidShowNotification object:nil];

    [[ NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(keyboardWillDisAppear:) name:UIKeyboardDidHideNotification object:nil];

 


-(void)viewWillDisappear:(BOOL)animated
 
    [[ NSNotificationCenter defaultCenter ] removeObserver:self ];
 

-(void)keyboardWillAppear:(NSNotification*) note
 
   const CGFloat default_gap = 25.0f;

   NSValue *keyBoardEndFrameValue = [[ note userInfo ] objectForKey:UIKeyboardFrameEndUserInfoKey ];

   CGRect keyBoardFrame = [ keyBoardEndFrameValue CGRectValue ];


   offset = scroll.contentOffset;

   UIWindow *window = [[ UIApplication sharedApplication ] keyWindow];
   UITextField *textField = (UITextField*)[ window performSelector:@selector(firstResponder) ];

   //Gap between keyboard origin and the scroll origin, relative to parent.
   CGFloat distanceRelativeToParent = keyBoardFrame.origin.y - scroll.frame.origin.y; 


   //Distance between superview to textfield inside scroll. to determine if it's necesary to scroll.
   CGFloat bound = (textField.frame.origin.y + textField.frame.size.height)+scroll.frame.origin.y; 

   CGFloat gapScroll = textField.frame.size.height+default_gap;

  if( bound >= keyBoardFrame.origin.y )
   
     [ UIView animateWithDuration:.3 delay:0.0 options:UIViewAnimationCurveEaseOut 
   animations:^

        [ scroll setContentOffset:CGPointMake(0, textField.frame.origin.y - distanceRelativeToParent +  gapScroll  ) animated:YES ];

   
  completion:^(BOOL finished)

   ];




-(void) keyboardWillDisAppear:(NSNotification*) note
   
   [ scroll setContentOffset:offset animated:YES ];

@end

【讨论】:

【参考方案3】:

UIViewControllers 有一个名为 interfaceOrientation 的属性和 UIInterfaceOrientationIsPortrait/Landscape 函数,所以基本上你可以这样做:

if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
//portrait logic

else
//landcapeLogic

在您的视图控制器中为每个 iPhone 和 iPad。从那里您可以像以前一样进行像素测量,因为据我所知,这是最简单的方法。

附:也有一个检查横向检查器的功能,但是如果第一个 if 语句是 false 意味着设备不是纵向的,那么它必须是横向的,因此是普通的 else。

【讨论】:

横向和上下颠倒怎么样?或者,纵向和横向属性是否包括倒置以及横向选项? 人像做任何事情都是正面朝上或上下颠倒,横向覆盖左右 好,我试试,如果有效,我会给你打勾。请给我一分钟=) 试过了。问题是,如果您在编辑设备时旋转设备,坐标不会改变,而且会惨遭失败。抱歉,我将不得不使用另一种方法。不过谢谢 抱歉,我应该提到您应该在视图控制器的 shouldRotateToInterfaceOrientation 方法中添加代码,以便根据您切换的方向将屏幕动画到新位置。也许对你的情况来说太复杂了,如果你不想尝试,我不怪你。

以上是关于在点击键盘上方移动文本字段的逻辑的主要内容,如果未能解决你的问题,请参考以下文章

自动向上滚动文本字段,实现类中没有任何逻辑

在键盘上方添加 UITextField

如何以编程方式移动 UIScrollView 以集中在键盘上方的控件中?

当文本字段获得焦点时,如何使底部工具栏浮在软键盘上方

如何将底页与具有文本字段的键盘一起移动(自动对焦为真)?

如何快速在键盘上添加文本字段?