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

时间:2012-02-03 20:45:46

标签: objective-c ios xcode uitextfield

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

我的问题的基本含义是,是否存在基于设备和方向获取键盘大小并自动使用该值并希望比此更快的逻辑。

如果这是最好的方式,请告诉我。否则,请提供意见。这是我的代码。 (这只是上移代码,而不是下移代码,以防止占用太多空间)

- (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];

} 

3 个答案:

答案 0 :(得分:18)

您真正想要做的是观察UIKeyboard(已经过|将要)(显示|隐藏)通知。它们在userInfo词典中包含开始和结束帧,以及正确的动画曲线和持续时间。

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

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

下面是一个示例视图控制器实现。此视图控制器的笔尖只是一个文本字段,其中连接了一个插座,文本字段的委托设置为视图控制器。

@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

答案 1 :(得分: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

答案 2 :(得分:0)

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

if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation){
//portrait logic
}
else{
//landcapeLogic
}

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

P.S。还有一个功能可以检查横向检查器,但是如果第一个if语句是假的,意味着设备不是纵向的,那么它必须是横向的,因此是普通的。