lionheart / LHSKeyboardAdjusting

An easy-to-use Objective-C protocol that automatically resizes / adjusts views when a keyboard appears on iOS.
http://lionheartsw.com
Apache License 2.0
100 stars 10 forks source link

implementation assumes view controller frame goes to bottom of window #5

Closed nsixbdg closed 9 years ago

nsixbdg commented 9 years ago

In the case of a form sheet presentation or even a contained view controller that doesn't extend to the bottom of the screen, the constraint's constant value calculations are incorrect (doesn't account for space between bottom of view controller and bottom of window)

In addition, I don't believe that rotation is accounted for in < iOS8. iOS8 nicely applies transforms to all the rectangles that you're accessing in the implementation. in <= iOS7 the transforms are not applied and need to be manually applied.

dlo commented 9 years ago

Great finds, thanks for pointing these out. When you say manually applied, what do you mean?

nsixbdg commented 9 years ago

In lhs_keyboardDidShow: you have

        CGRect frame = [sender.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
        CGRect newFrame = [self.view convertRect:frame fromView:[[UIApplication sharedApplication] delegate].window];

both rectangles here do not have a rotation transform applied. It is most obviously seen by looking at the height and width of the keyboard's frame when in landscape - they appear to be swapped. So I have done something along these lines (below) which isn't quite right, I must admit. I stumbled across LHSKeyboardAdjusting category when looking for a solution to the issues I initially pointed out in this bug report. I was kinda hoping you had already figured it out for me. If I figure out the right code bits to properly solve the rotation issue I'll submit a pull request.

    // newRect is a frame in window coordinate system
    CGFloat centerX = CGRectGetMidX(newRect);
    CGFloat centerY = CGRectGetMidY(newRect);

    CGFloat angle;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
    switch (interfaceOrientation) {
        case UIInterfaceOrientationPortrait:
            angle = 0;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            angle = M_PI;
            break;
        case UIInterfaceOrientationLandscapeLeft:
            angle = - M_PI_2;
            break;
        case UIInterfaceOrientationLandscapeRight:
            angle = M_PI_2;
            break;
        default:
            break;
    }
    CGAffineTransform translate = CGAffineTransformMakeTranslation(centerX, centerY);
    CGAffineTransform rotate = CGAffineTransformMakeRotation(angle);
    CGAffineTransform xform = CGAffineTransformConcat(translate, rotate);
    xform = CGAffineTransformConcat(xform, CGAffineTransformInvert(translate));
    // finalRect should be rotated frame in window coordinate system; something is off though
    CGRect finalRect = CGRectApplyAffineTransform(newRect, xform);

If you can run with this hints, I'd be delighted to see what you come up with.

nickbit commented 9 years ago

To solve the space problem: I added a method in the protocol

-(CGFloat)distanceFromKeyboard;

Then change

- (void)lhs_keyboardWillHide:(NSNotification *)sender {
...
        self.keyboardAdjustingBottomConstraint.constant = -[self distanceFromKeyboard];
...

and

- (void)lhs_keyboardDidShow:(NSNotification *)sender {
...
        self.keyboardAdjustingBottomConstraint.constant = newFrame.origin.y - CGRectGetHeight(self.view.frame) - [self distanceFromKeyboard];
...

in UIViewController+LHSKeyboardAdjustment.m

and add the implementation of the new method in your UIViewController

-(CGFloat)distanceFromKeyboard {
  return 20;
}
nsixbdg commented 9 years ago

A friend suggested this elegant solution - get the keyboard's frame expressed in the viewController's coordinate space. then the arithmetic of the offset becomes trivial. see below -

- (void)keyboardNotification:(NSNotification*)notification {
    NSDictionary* keyboardInfo = [notification userInfo];
    NSValue* keyboardFrameEnd = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardFrameEndRect = [keyboardFrameEnd CGRectValue];

    CGRect r = [self.view convertRect:keyboardFrameEndRect fromView:nil];
    self.keyboardAdjustingBottomConstraint.constant = self.view.bounds.size.height - r.origin.y;
}

This nicely addresses all the issues I was running into - formsheet presentation and rotation calculation is already baked in.

dlo commented 9 years ago

@nsixbdg I like it! Mind submitting a PR?

nsixbdg commented 9 years ago

Glad you like it @dlo . It feels like the right solution. PR submitted

mthole-old commented 9 years ago

This issue should be closed now, right?

nsixbdg commented 9 years ago

Indeed it is

Sent from my iPhone

On Aug 3, 2015, at 15:57, Michael Thole notifications@github.com wrote:

This issue should be closed now, right?

― Reply to this email directly or view it on GitHub.

dlo commented 9 years ago

Sorry @nsixbdg, I dropped the ball on this. Fixed in #6