iOSProgrammingIsFun
iOSProgrammingIsFun

Reputation: 1458

iOS 7 - SplitViewController Detail View - Autolayout UITextView Keyboard Orientation Change

I can't believe I've been stuck on this for over a week.

I've seen (and tried) every other Stack question / answer on this I could find and none work.

Basically I have a detail view with a toolbar and underneath a UITextView that takes up the rest of the space leaving a 20 point border around it's edges to the edge of the superview.

All I need is when the keyboard is displayed the textview will either change it's frame or it's content inset stuff, so that the keyboard doesn't cover anything up and the text scrolls to the end of it's text, and any new typing / line wrapping is not hidden by the keyboard - simple right? Er... no.

If the user changes Orientation (all 4 supported) then it needs to adjust to accommodate.

Then with keyboard dismissal it needs to return to it's full size ( depending on possible new orientation ).

This is the first project I've done with both Autolayout and iOS 7 (and I've run into the bug in iOS7 that puts your new line of text 'below' the bottom of the text view, but thanks to a stack fix that's okay now.)

However NONE of the solutions I've tried from this site work.

I'm setting the constraints for the UITextView by positioning it in IB in portrait and selecting 'reset to suggested constraints' - that seems to lay it out correctly for all 4 orientations if the keyboard is not displayed.

Upvotes: 0

Views: 855

Answers (3)

iOSProgrammingIsFun
iOSProgrammingIsFun

Reputation: 1458

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

if ( kbSize.height < kbSize.width )

This was the only change required to the answer above by rdelmar. Thanks so much! This drove me mad for a week!!!!

Upvotes: 0

iOSProgrammingIsFun
iOSProgrammingIsFun

Reputation: 1458

The suggested code fix above from the incredibly helpful rdelmar works perfectly in portrait. Changing to landscape however produces this crash:

Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x941da50 V:|-(158)-[UITextView:0x9926000]   (Names: '|':UIView:0x9449a30 )>",
    "<NSLayoutConstraint:0x9449a00 V:[UITextView:0x9926000]-(1044)-|   (Names: '|':UIView:0x9449a30 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x97b2d70 h=--& v=--& V:[UIView:0x9449a30(768)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x9449a00 V:[UITextView:0x9926000]-(1044)-|   (Names: '|':UIView:0x9449a30 )>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Now, I've cleared EVERY constraint from my detail view, and started over. The UILabel, UIToolBar and UITextView have all had their leading, trailing and top edges PINNED.

The UITextView also had it's BOTTOM EDGE PINNED.

And this bottom constraint is the one linked to the IBOutlet mentioned in the above post.

Any more ideas what's going wrong?

Upvotes: 0

rdelmar
rdelmar

Reputation: 104082

It can be done by adjusting the constraint to the bottom of the view when the keyboard appears and disappears. In the example below, I have a view controller with a tool bar and a text view. The text view has constraints (with a value of 20) to the bottom and sides of the main view, and one to the tool bar at the top of the view. I have an IBOutlet to the constraint to the bottom of the view. Notice that in the keyboardWillShow: method, I have to check on the orientation of the view in order to get the constraint's constant value correct -- in landscape mode, the keyboard's width and height are reversed (that is, what you get as size.width is actually the height, and size.height gives you the width).

@interface ViewController ()
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomCon; // outlet to the constraint between the text view and the bottom of the view
@property (weak,nonatomic) IBOutlet UITextView *tv; // outlet for the text view
@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}



- (void)keyboardWillShow:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    if (self.view.bounds.size.width < self.view.bounds.size.height) {
        self.bottomCon.constant = kbSize.height + 20;
    }else{
        self.bottomCon.constant = kbSize.width + 20;
    }
}


-(void)keyboardDidShow:(NSNotification *) aNotificaation {
    [self.tv scrollRangeToVisible:NSMakeRange(self.tv.text.length - 1, 1)];
}


- (void)keyboardWillHide:(NSNotification*)aNotification {
    self.bottomCon.constant = 20;
}

-(IBAction)finishedEditing:(id)sender { // action for "Done" button on tool bar
    [self.tv resignFirstResponder];
}

Upvotes: 1

Related Questions