Reputation: 371
I am writing a custom keyboard for iOS 8. My main UIView returns {{0, 0}, {0, 0}}
in my viewDidLoad
method. I have tried receiving the CGRect with view.frame and bounds but both return 0. However if I use these same methods to retrieve my view's coordinates in the viewDidAppear
method they return fine: {{0, 0}, {320, 216}}
. The problem here is that viewDidAppear runs after didLoad so I cannot retrieve the size from didAppear and use it in didLoad. Here is my question:
Why does self.view 's frame return 0 in viewDidLoad
? Shouldn't its size be set already in here? This (viewDidLoad) is where I'm supposed to be doing most of my initiation and UI set up, correct? I have moderate experience in Xcode.
I am programming this in swift, although this shouldn't matter(?) I thought it was worth noting. Answers in Obj-C are fine.
Edit: I created an entirely new Xcode project and target with the following class and receive the same error:
import UIKit
class KeyboardViewController: UIInputViewController {
override func viewDidLoad() {
super.viewDidLoad()
println(self.view.frame) // returns (0.0,0.0,0.0,0.0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidAppear(animated: Bool) {
println(self.view.frame) // returns (0.0,0.0,320.0,216.0)
}
}
I've tested with the simulator and physical devices too ranging from 6 to 4S. Nothing seems to make a difference.
Upvotes: 2
Views: 1552
Reputation: 19524
I could get it to work by adding a textField on top and making it FirstResponder:
import UIKit
class KeyboardViewController: UIInputViewController {
@IBOutlet var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.becomeFirstResponder()
println(self.view.frame) // returns (0.0,0.0,375.0,667.0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidAppear(animated: Bool) {
println(self.view.frame) // returns (0.0,0.0,375.0,667.0)
}
}
Upvotes: 0
Reputation: 8872
It is a general property of the view display hierarchy (not only of keyboard extensions) that the frame size will not be correct in viewDidLoad. See here and here which also gives some suggestions on how to handle layout.
I would recommend using auto layout (similar to how "nextKeyboardButton" is done in the keyboard extension example code) in which case for the most part you won't have to worry about handling frame changes. E.g. in viewDidLoad
MyKeyboardView* keyboardView = [[keyboardView alloc] init];
keyboardView.translatesAutoresizingMaskIntoConstraints = NO;
[self.inputView addSubview: keyboardView];
NSLayoutConstraint *leftSideConstraint = [NSLayoutConstraint constraintWithItem:keyboardView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.inputView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0];
NSLayoutConstraint *rightSideConstraint = [NSLayoutConstraint constraintWithItem:keyboardView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.inputView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:keyboardView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.inputView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:keyboardView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.inputView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
[self.inputView addConstraints:@[leftSideConstraint, rightSideConstraint, bottomConstraint, topConstraint]];
In this way, the frame for your keyboardView will track the inputView frame (which is set to the default keyboard frame size for the orientation and device) and will therefore resize automatically with orientation changes. You can then handle further custom layout in layoutSubviews of your MyKeyboardView class. One last thing, if your MyKeyboardView does any custom drawing in drawRect, you will need to set the contentMode in MyKeyboardView's init self.contentMode = UIViewContentModeRedraw;
otherwise drawRect won't be called upon frame changes.
Upvotes: 1
Reputation: 150
You should check with self.inputView.frame
instead of self.view.frame
for custom keyboard
You can use isPortraitLayout method to check/initialise view if its landscape mode or portrait mode...
-(BOOL) isPortraitLayout{
int appExtensionWidth = (int)round(self.view.frame.size.width);
int possibleScreenWidthValue1 = (int)round([[UIScreen mainScreen] bounds].size.width);
int possibleScreenWidthValue2 = (int)round([[UIScreen mainScreen] bounds].size.height);
int screenWidthValue;
if (possibleScreenWidthValue1 < possibleScreenWidthValue2) {
screenWidthValue = possibleScreenWidthValue1;
} else {
screenWidthValue = possibleScreenWidthValue2;
}
return (appExtensionWidth == screenWidthValue);
}
Upvotes: 1