0
votes

I have a viewController with 3 views: topView, tableView and textView.

I want them to layout like this:

in portrait mode -

|---------------|  
|    topView    |  
|---------------|
|               |
|               |
|   tableView   |
|               |
|               |
|---------------|               
|   textView    |
|---------------|

in landscape mode:

|--------------------------|  
|         topView          |  
|--------------------------|
|                          |
|        tableView         |
|--------------------------|               
|        textView          |
|--------------------------|

And when keyboard is up:

|---------------|  
|               |
|   tableView   |
|               |
|---------------|               
|   textView    |
|---------------|  
|               |
|   keyboard    |
|               | 
|---------------|  

|--------------------------|  
|        tableView         |
|--------------------------|               
|        textView          |
|--------------------------| 
|                          |
|        keyboard          |
|--------------------------|  

(as you can see the top view is gone when keyboard is up)

the code for doing this is:

- (void)loadView
{
    [super loadView];

    // load top view
    _topView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, TOP_VIEW_HEIGHT)];
    _topView.autoresizingMask =  UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
    _topView.backgroundColor = [UIColor redColor];
    [self.view addSubview:_topView];

    // load table view (at the middle)
    CGRect tableFrame = CGRectMake(0, TOP_VIEW_HEIGHT, self.view.bounds.size.width, self.view.bounds.size.height - TOP_VIEW_HEIGHT - TEXT_VIEW_HEIGHT);
    _tableView = [[UITableView alloc] initWithFrame:tableFrame style:UITableViewStylePlain];
    _tableView.autoresizingMask =  UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [self.view addSubview:_tableView];

    // load text view (at the bottom)
    CGRect textViewFrame = CGRectMake(0, tableFrame.size.height + TOP_VIEW_HEIGHT, self.view.bounds.size.width, TEXT_VIEW_HEIGHT);
    _textView = [[UITextView alloc] initWithFrame:textViewFrame];
    _textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
    _textView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:_textView];
}  



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

    // Get animation info from userInfo
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;


    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];

    CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect textViewFrame = self.textView.frame;
    textViewFrame.origin.y -= kbSize.height;

    CGRect topViewFrame = self.topView.frame;
    topViewFrame.origin.y -= topViewFrame.size.height;

    CGRect tableFrame = self.tableView.frame;
    tableFrame.origin.y -= topViewFrame.size.height;
    tableFrame.size.height -= (kbSize.height - topViewFrame.size.height);

    [UIView animateWithDuration:animationDuration delay:0.0 options:animationCurve animations:^{
        self.textView.frame = textViewFrame;
        self.tableView.frame = tableFrame;
        self.topView.frame = topViewFrame;
    }completion:^(BOOL finished) {

    }];
}

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

    // Get animation info from userInfo
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;


    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];

    CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect textViewFrame = self.textView.frame;
    textViewFrame.origin.y += kbSize.height;

    CGRect topViewFrame = self.topView.frame;
    topViewFrame.origin.y += topViewFrame.size.height;

    CGRect tableFrame = self.tableView.frame;
    tableFrame.origin.y += topViewFrame.size.height;
    tableFrame.size.height += kbSize.height - topViewFrame.size.height;

    [UIView animateWithDuration:animationDuration delay:0.0 options:animationCurve animations:^{
        self.textView.frame = textViewFrame;
        self.tableView.frame = tableFrame;
        self.topView.frame = topViewFrame;
    }completion:^(BOOL finished) {
        //
    }];
}

Most of what I want works well, the problem is when keyboard is shown in landscape mode, then things goes wrong..

Please pay attention to the views autoresizingMask property, because I'm not sure I set it currently.

2

2 Answers

1
votes

For auto rotating, try setting the top view's mask to just flexible width, the middle one to flexible width and flexible height, and the text view, flexible width and top margin. I doubt that will work without a hitch, but it's worth a try. You can override willAnimateRotationToInterfaceOrientation:duration: on your view controller for custom work. I'm pretty sure that basic auto rotating masks can't handle this kind of layout, but I'd love to be proven wrong.

Also check the orientation in loadView like so:

if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
    // do one layout
} else {
    // do another layout
}

I am doing very custom rotation work too in my app (think custom split view controller from the ground up--yuck) and I am doing it using willAutorotate and UIInterfaceOrientationIsLandscape.

This may not apply to you because of the way you worded your question: I'm not sure whether the problem is when you have the keyboard open, then rotate to landscape (in which case this answer might be helpful); or whether you have problems when you open the keyboard in landscape (in which case this answer might not pertain to you as much).

1
votes

I found the problem, When I did the view's up/down animation in keyboardWillShow/willHide I didn't converted the keyboard rect from screen to view coordinates

CGRect kbRect = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
kbRect = [self.view convertRect:kbRect fromView:nil];
CGSize kbSize = kbRect.size; 

Now it's working fine :)