5

I'm using the below code to shift a view and my tableview up when my keyboard is activated. When the keyboard is closed however, it takes the upView a solid 2 seconds after the keyboard closes to return to where it was (the tableView on the other hand, is instant). Why is this happening?

      - (void)viewDidLoad {
            [super viewDidLoad];

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


        }

        - (void)keyboardWillChange:(NSNotification *)notification {


            NSDictionary* keyboardInfo = [notification userInfo];

            NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];

            CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];

            UITabBarController *tabBarController = [UITabBarController new];
            CGFloat tabBarHeight = tabBarController.tabBar.frame.size.height;


            self.keyboardHeight = keyboardFrameBeginRect.size.height - tabBarHeight;

        }


        - (void) animateTextView:(BOOL) up
         {

                const int movementDistance = self.keyboardHeight;

                const float movementDuration = 0.2f;
                int movement= movement = (up ? -movementDistance : movementDistance);


                [UIView beginAnimations: @"anim" context: nil];
                [UIView setAnimationBeginsFromCurrentState: YES];
                [UIView setAnimationDuration: movementDuration];

                self.upView.frame = CGRectOffset(self.upView.frame, 0, movement);
                [UIView setAnimationDidStopSelector:@selector(afterAnimationStops)];
                [UIView commitAnimations];

                self.tableView.frame = CGRectOffset(self.tableView.frame, 0, movement);
                [UIView setAnimationDidStopSelector:@selector(afterAnimationStops)];
                [UIView commitAnimations];

        }

    - (void)textViewDidBeginEditing:(UITextView *)textView
    {

     [self animateTextView:YES];

    }

- (void)textViewDidEndEditing:(UITextView *)textView
{
    [self animateTextView:NO];
}

UPDATED CODE

.m

- (void)handleKeyboard:(NSNotification*)aNotification{
    NSDictionary* info = [aNotification userInfo];
    NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval duration = 3;
    [value getValue:&duration];
    if (aNotification.name == UIKeyboardWillHideNotification) {
        /** KEYBOARD HIDE **/

       [UIView animateWithDuration:0 animations:^{ self.upView.frame = CGRectOffset(self.upView.frame, 0, self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, self.keyboardHeight); } completion:^(BOOL finished) {}];


        [self moveCustomView:NO duration:duration];
        NSLog(@"CLOSED!");
    }

    if (aNotification.name == UIKeyboardWillShowNotification) {
        /** KEYBOARD SHOW **/

 [UIView animateWithDuration:0 animations:^{ self.upView.frame = CGRectOffset(self.upView.frame, 0, -self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -self.keyboardHeight); } completion:^(BOOL finished) {}];


        [self moveCustomView:YES duration:duration];
    }
}

- (void)moveCustomView:(BOOL)move duration:(NSTimeInterval)time{

}
Naresh
  • 16,698
  • 6
  • 112
  • 113
Brittany
  • 1,359
  • 4
  • 24
  • 63
  • Are you (somewhere) also registering for the `UIKeyboardWillHideNotification`? – DonMag Jan 29 '18 at 19:16
  • @DonMag See edited code above - I'm using keyboardWillChange but no, not willHideNotification. – Brittany Jan 29 '18 at 19:17
  • OK - you want to add a function to handle "keyboard will hide" - then essentially do the reverse of what you're doing for "keyboard will show". Lots and lots of examples out there. – DonMag Jan 29 '18 at 19:28
  • can you post the code where `animateTextView` is called? – janusfidel Jan 29 '18 at 19:33
  • @Brittany - start with Apple's docs: https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html#//apple_ref/doc/uid/TP40009542-CH5-SW16 – DonMag Jan 29 '18 at 19:34
  • @DonMag Ok, so why does adding keyboardWillHide keep my upView from delaying? Just trying to connect the dots lol – Brittany Jan 29 '18 at 19:38
  • @Brittany - well, you currently don't show where you're calling `animateTextView()` so it's a little tough to say exactly what's going on. The *standard* method is to register for both show and hide keyboard notifications, and then adjust your layout accordingly. – DonMag Jan 29 '18 at 19:46
  • @DonMag see animateTextView in edit above – Brittany Jan 29 '18 at 19:52
  • @Brittany the doc says, use of `commitAnimations` is discouraged in iOS 4 and later, have you tried using `animateWithDuration` ? `[UIView animateWithDuration:movementDuration animations:^{ self.upView.frame = CGRectOffset(self.upView.frame, 0, movement); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, movement); } completion:^(BOOL finished) {}]` – janusfidel Jan 29 '18 at 20:14

2 Answers2

5

This issue might be with the animation duration, so you can get the keyboard showing and hiding animation duration from the -(void)handleKeyboard:(NSNotification *)notification {}

and also handle the showing and hiding your custom view inside the same function. Add the following code to your viewDidLoad function

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

Handle keyboard actions and UI changes

- (void)handleKeyboard:(NSNotification*)aNotification{
    NSDictionary* info = [aNotification userInfo];
    NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval duration = 0;
    [value getValue:&duration];
    if (aNotification.name == UIKeyboardWillHideNotification) {
        /** KEYBOARD HIDE **/

        //calculate your view frames and handle UI changes
        /*
         .
         .
         .
         .
         .
         */
        [self moveCustomView:NO duration:duration];
    }

    if (aNotification.name == UIKeyboardWillShowNotification) {
        /** KEYBOARD SHOW **/

        //calculate your view frames and handle UI changes
        /*
         .
         .
         .
         .
         .
         */
        [self moveCustomView:YES duration:duration];
    }
}

- (void)moveCustomView:(BOOL)move duration:(NSTimeInterval)time{

}
Jayachandra A
  • 1,335
  • 1
  • 10
  • 21
  • This works seamlessly, with one exception: For some reason when I hide my keyboard, it executes keyboardWillHideNotification twice? I placed a log inside of keyboardWillHide, and the console shows it twice (in other words, my uiview moves down further than necessary?) I've skimmed my code for potential duplicates, and nothing else is present :/ – Brittany Feb 06 '18 at 07:48
  • @Brittany Please check how many time you have been added UIKeyboardWillHideNotification notification? – Jayachandra A Feb 06 '18 at 07:52
  • I only have it once - that said, I do have keyboardWillChange notification in order to grab the height of the keyboard in my viewDidLoad - would that be affecting it? I'd assume not, as it doesn't "show" twice? – Brittany Feb 06 '18 at 07:54
  • @Brittany Yes, that would be the problem, you can use only UIKeyboardWillHideNotification and UIKeyboardWillShowNotification, using these two observers it is very easy to handle keyboard and other UI frame changes. – Jayachandra A Feb 06 '18 at 09:21
1

I think you need to use thread to call animation immediately...

- (void)textViewDidBeginEditing:(UITextView *)textView {

    dispatch_async(dispatch_get_main_queue(), ^{
        [self animateTextView:YES];
    });
}

- (void)textViewDidEndEditing:(UITextView *)textView {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self animateTextView:NO];
    });
}

I'm not much aware of your problem, but try this because if we got this type of problems dispatch_async() will solve.

Naresh
  • 16,698
  • 6
  • 112
  • 113