Question

I'm trying to create a simple modal view controller that lets you edit text using a text view. However, when I present the view controller modally, it slides in from the bottom left direction instead of just sliding in from the bottom.

Here's a video of the weird effect: http://youtu.be/9M_MHA5mt1M

My controller simply watches for the keyboard to show and then resizes the text view using auto layout appropriately. Here's the code:

#import "TextPicker.h"

@interface TextPicker ()

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeight;

@end

@implementation TextPicker

- (id)initWithText:(NSString *)text
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
    self = [storyboard instantiateViewControllerWithIdentifier:@"textPicker"];
    if (self) {
        self.text = text;

    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self observeKeyboard];

    //self.textView.text = self.text;
    [self.textView becomeFirstResponder];
}


- (void) viewWillDisappear:(BOOL)animated {
    [self.textView resignFirstResponder];
}

- (IBAction)savePressed:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];    
}

- (IBAction)cancelPressed:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void) dealloc {
    [self stopObervingKeyboard];
}

- (void)observeKeyboard {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- (void)stopObervingKeyboard {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardFrame = [kbFrame CGRectValue];
    self.keyboardHeight.constant = -keyboardFrame.size.height;

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];
    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    self.keyboardHeight.constant = 0;
    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (IBAction)dismissKeyboard:(id)sender {
    [self.textView resignFirstResponder];
}


@end
Was it helpful?

Solution

Your view is animating as you have asked it to by wrapping the [self.view layoutIfNeeded] call inside an animation block.

In viewDidLoad you begin observing keyboard changes, and when you detect them you animate the adjustments, this is normally correct. But then, before the view does its first layout, you show the keyboard; this results in an animation for all the views from CGRectZero to their proper sizes. And this is the effect you are seeing.

So basically you need to give the view a chance to layout before your animated layoutIfNeeded call. Probably the easiest way to do this is simply to move [self.textView becomeFirstResponder]; to either viewWillAppear: or viewDidAppear:.

*As a side note, remember to call super in appearance calls. I noticed you did not call [super viewWillDisappear];.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top