Blog

iOS ObjectiveC

iMessage style keyboard in iOS 8

After spending the last days with making my iOS App, Boutiquiee, ready for iOS 8, I wanted to share my thoughts and findings. First to sum up what I mean by iMessage style. I would say 90% of the known apps that feature comments or messages have this kind of keyboard, that has the input field above the keyboard and is dismissed when scrolling down and touching the keyboard. The way I had it done in iOS 5 till iOS 7 was by using an inputAccessoryView. InputAccessoryViews are made exactly for this task, and I was really confused, when I could not get it to work in iOS 8, and I wonder, if others have had similar problems. The problem I could not solve, was a really strange bug when tapping into the textfield, the keyboard would fly around the screen like a balloon loosing air. I made a minimal project and there was the same problem. I could solve it with crazy timeouts but that introduced other bugs. In the end I chose the second way: adding the input field and controls to the window and listening to keyboard frame changes:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardFrameWillChange:) name:
     UIKeyboardWillChangeFrameNotification object:nil];
-(void) keyboardFrameWillChange:(NSNotification*)msg {
    NSDictionary *info = [msg valueForKey:@"userInfo"];
    CGRect endframe = [[info valueForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
    self.textInput.newKeyboardFrame = endframe;

    [UIView animateKeyframesWithDuration:[[info valueForKey:@"UIKeyboardAnimationDurationUserInfoKey"] floatValue] delay:0 options:[[info valueForKey:@"UIKeyboardAnimationCurveUserInfoKey"] integerValue] animations:^{￿

        [self.textInput adjustSizeForTextView:self.textInput.inputField];
    } completion:^(BOOL finished) {
       self.textInput.keyboardFrame = endframe;
    }];

}

That works well, because the notifications contain not only frames but also animation information. Still it is strange to do it that way, because using an inputAccessoryView was much easier and made more sense technically. I do not understand why it stopped working in iOS 8.

The second challenge was the keyboard dismissing. This challenge was even more annoying, because since iOS 7 UIScrollViews have the property UIScrollViewKeyboardDismissModeInteractive which should do exactly this needed thing. The problem is, that there is no way to track the keyboard while panning the keyboard. In iOS 7 you could add an observer for the frame property, but that does not work in iOS 8, so the whole thing is useless. There maybe a workaround by observing the properties of the CALayer http://stackoverflow.com/a/19687115/965686! I have currently no time to check it out, but it seems promising.

So that is what I did:

  • Add a fake input accessory view with the same dimensions as the text input view
  • to resize the accessory view you have to set the frame for iOS 7 and the layout constraint constants for height and width in iOS 8 (took me some time to get that one..)
  • after the keyboard shows catch it by using yourInputAccessoryView.superview
  • add touchesBegan, touchesMoved, touchesEnded functions to the scrollview that contains the messages, comments etc
  • check the touches and move the keyboard from step two according to the touches

That again works well, but it is of course much more complicated.

So in the end everything works well in iOS 7 and iOS 8, but I wonder why such a common task must be so complicated, especially because the needed functions exist but they do not work (for me?)!