4

I have a problem with Keyboard Extension on iOS (real) device during recoding or phone call (iOS Simulator doesn't have red status bar). Because of the status bar increases 20 points, the custom keyboard also moves 20 points in Y-axis and decreases its height to 196 points (it should be 216 points). However, when I print the view.frame, it shows {{0.0, 0.0}, {320.0, 196.0}}.

Here is the screenshot.

If I use storyboard instead of programmatically adding views, it works fine. First I thought it's because of topLayoutGuide.length, but it shows 0.0 in the debug area.

I has tried to find solution or any topics related to this problem but it seems like me alone facing it. :(

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
João Oliveira
  • 422
  • 3
  • 17
  • It's very simple to jump into this problem. You just add a keyboard extension to your new project, add a line of code `view.backgroundColor = UIColor.white()` to identify the keyboard's view to your `keyboardViewController.swift`, and run the project, you will see the problem. – João Oliveira Oct 09 '15 at 02:07
  • I think it's iOS 9 bug. – João Oliveira Oct 12 '15 at 18:29
  • I've got stuck to the same issue. It reproduces on both iOS 9.0 and iOS 9.1(fine on iOS 8). Have you reported a radar on this? I would like to duplicate it. **Off-topic**: You can simulate the In-Call status bar in iOS Simulator: `Hardware => Toggle In-Call Status Bar` or `CMD+Y` – thelvis Nov 02 '15 at 18:06
  • Yeah, I guess it's a bug in iOS 9. It does not happen to only keyboard extension but also UITabBar. Hope it is fixed soon. Oh! Thanks for the tip! – João Oliveira Nov 03 '15 at 23:46
  • i've tested iOS 9.2 beta bug is still there – TomSawyer Nov 17 '15 at 06:46
  • @thelvis Did you file radar? Mind sharing link to it? – Rasto Feb 20 '16 at 02:45

2 Answers2

9

A workaround that works to me:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    if (CGRectGetMinY(self.view.superview.frame) > 0.f) {
        CGRect frame = self.view.superview.frame;
        frame.origin.y = 0.f;
        [self.view.superview setFrame:frame];
    }
}

Basically, we're looking for superview's frame and I "adjust" it if it gets shifted.

Edit:

As TomSawyer mentioned, there is an issue with the previous solution. This one should solve them both.

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    CGRect frame = self.view.superview.frame;
    CGFloat dy = CGRectGetMinY(frame);
    if (dy > 0.f) {
        frame.origin.y = 0.f;
        frame.size.height += dy;
        [self.view.superview setFrame:frame];
    }
}
Community
  • 1
  • 1
thelvis
  • 458
  • 3
  • 12
  • It fixes the view, but after i added touches event to the view, it can't recognize the touch in the bottom 20 pixels. How to fix the touch event also? – TomSawyer Dec 21 '15 at 09:59
  • The edit still does not work for me. The visual missplacement is fixed but last bottom 20 points of the keyboard do not react to touches. – Rasto Feb 20 '16 at 02:47
  • @drasto Have you put the code in the subclass of `UIInputViewController`? – thelvis Feb 22 '16 at 10:57
  • 1
    @drasto Regarding the radar: The ticket number is 23357303, which Apple marked as `Duplicate of 22973486 (Open)`. Note that it's on Apple's private radar, not the public one. I think I can copy the content to a public ticket if you want to. – thelvis Feb 22 '16 at 11:00
  • You are right, it works. My project is in Swift so I was translating your code to Swift and made very stupid error in the process. My loss is your profit in this case +250 reputation. Congratulation, you might just set StackOverflow record! I have never seen anybody even close to your reputation (21) to win this big a bounty! You earned it well. As for the radar, it would be great if you could make it public and write me how to find and duplicete the ticket – Rasto Feb 24 '16 at 00:12
  • @drasto Thank you! I've copied the content into a [public radar](http://www.openradar.me/radar?id=5033296232710144). What you can do now is to, basically, copy the content(more or less) into a new ticket on [Apple's Bug Report page](https://bugreport.apple.com). The more duplicates, the bigger the chance Apple will fix it. – thelvis Feb 24 '16 at 21:54
  • Thank you I will duplicate. To @JoaoOliveira: I believe this answer should be marked as accepted. – Rasto Feb 27 '16 at 00:17
  • @thelvis If you have some time you might be interested in [one question of mine](http://stackoverflow.com/q/36145450/311865). It also has something to do with wrong keyboard position - this time cased by incorrect height after rotation. I would be very thankful for your help. – Rasto Mar 22 '16 at 03:19
  • this worked for me but when called in the viewDidAppear not in the viewDidLayoutSubviews, thanks ! – Red Mak May 22 '16 at 01:18
0

you can write a workaround using the UIApplicationWillChangeStatusBarFrameNotification.

In your init or viewDidLoad:

let os = NSProcessInfo().operatingSystemVersion
if os.majorVersion == 9 && (os.minorVersion == 0 || os.minorVersion == 1) {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "statusBarChange:", name:
        UIApplicationWillChangeStatusBarFrameNotification, object: nil)
}

And handling the notification:

func statusBarChange(notification:NSNotification) {
    let newRect:CGRect? = notification.userInfo?[UIApplicationStatusBarFrameUserInfoKey]?.CGRectValue
    var heightOffset = CGFloat(20) - newRect!.height
}

You can then update the view frame using the offset as Y coordinate.

Hope that helps.

Bert Vermeire
  • 416
  • 4
  • 7
  • It doesn't work. the trouble is inputView is automatically shrink down and get shorter height. can't do anything to pull it up 20 pixels – TomSawyer Nov 17 '15 at 06:49
  • @TomSawyer You are right, I also cannot find any way how to compensate for that 20 points loss of height. – Rasto Feb 20 '16 at 03:05