iOS: 在 iPad 模态视图中获取键盘点的顶部?
iOS: Get top of keyboard point in iPad modal view?
我需要在显示键盘时调整 'message bar',并且在使用 iPad 模态视图控制器时遇到问题。 'message bar' 在显示时应该位于键盘的正上方,然后在隐藏键盘时位于模式的底部(消息应用程序样式)。
问题是我需要根据 Modal 的坐标系获取键盘框架的最高点。
我发现这个答案在理论上似乎是正确的,但不起作用 (How can I find portion of my view which isn't covered by the keyboard (UIModalPresenationStyleFormSheet)?):
仅供参考当显示键盘时,主要 window 中的键盘框架(即 'keyboardFrame')= (-84.0, 526.0, 768.0, 264.0)。为模态视图控制器坐标系(即 'newSize')转换时的键盘框架 = (-168.0, 292.0, 768.0, 264.0)*
// Convert the keyboard rect into the view controller's coordinate system
// The fromView: nil means keyboardRect is in the main window's coordinate system
let newSize = self.view.convertRect(keyboardFrame, fromView: nil)
// And then this is the part that gets covered!
let keyboardCoveredHeight = self.view.bounds.height - newSize.origin.y
self.messageToolbar.bottomConstraint.constant = -keyboardCoveredHeight
我认为您 运行 遇到了以下两个问题之一(也许两者都有):
- 在iOS8中,你必须将键盘的矩形从屏幕的坐标转换为space
- 在 iPad 上,sheet 视图有时会在显示键盘时向上移动一点,这发生在 键盘显示之后,因此您需要在
viewWillLayoutSubviews
中再次计算结果
这里是a sample project that does what you want。
为了后代,这里是有趣的源代码:
class TypingViewController: UIViewController {
var keyboardHoverView: UIView! // your keyboard toolbar or whatever
var lastKeyboardFrame : CGRect! // whenever you get a frame update, store it here
override func viewDidLoad() {
super.viewDidLoad()
createKeyboardHoverView()
observeKeyboard()
}
func createKeyboardHoverView() {
// make your keyboard toolbar
keyboardHoverView = view
}
func observeKeyboard() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification : NSNotification) {
let dict = notification.userInfo!
let frameValue = dict[UIKeyboardFrameEndUserInfoKey] as! NSValue
lastKeyboardFrame = frameValue.CGRectValue()
moveKeyboardView()
}
func keyboardWillHide(notification : NSNotification) {
moveKeyboardView()
}
override func viewWillLayoutSubviews() {
// this moves the view again, in case the modal view has shifted up
moveKeyboardView()
}
func moveKeyboardView() {
if lastKeyboardFrame != nil {
// this conversion is used in iOS 8 and differs from most online tutorials
let frameInThisView = self.view.convertRect(lastKeyboardFrame, fromCoordinateSpace: view.window!.screen.coordinateSpace)
var newRect = keyboardHoverView.frame
newRect.origin.y = frameInThisView.origin.y - CGRectGetHeight(newRect)
keyboardHoverView.frame = newRect
println("Setting rect: \(newRect)")
}
}
}
我最终使用熟悉的类别在 iPad 模态视图中获得正确的键盘框架:
- (CGFloat)heightCoveredByKeyboardOfSize:(CGSize)keyboardSize
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
CGRect frameInWindow = [self convertRect:self.bounds toView:nil];
CGRect windowBounds = self.window.bounds;
CGFloat keyboardTop;
CGFloat heightCoveredByKeyboard;
//Determine height of the view covered by the keyboard relative to current rotation
switch (orientation)
{
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
keyboardTop = windowBounds.size.height - keyboardSize.height;
heightCoveredByKeyboard = windowBounds.size.height - frameInWindow.origin.y - keyboardTop;
break;
case UIInterfaceOrientationPortraitUpsideDown:
default:
keyboardTop = windowBounds.size.height - keyboardSize.height;
heightCoveredByKeyboard = CGRectGetMaxY(frameInWindow) - keyboardTop;
break;
}
return MAX(0.0f,heightCoveredByKeyboard);
}
连同 DAKeyboardControl(用于平移):
// Use [unowned self] in closure for weak reference
self.view.addKeyboardPanningWithFrameBasedActionHandler(nil, constraintBasedActionHandler: { [unowned self] (keyboardFrameInView, opening, closing) -> Void in
if opening
{
if UIDevice.isIpad()
{
// iPad requires a different method due to use of modal view
self.messageToolbar.bottomConstraint.constant = -self.view.heightCoveredByKeyboardOfSize(keyboardFrameInView.size)
}
else
{
self.messageToolbar.bottomConstraint.constant = -keyboardFrameInView.size.height
}
}
if closing
{
self.messageToolbar.bottomConstraint.constant = 0
}
self.view.updateConstraintsIfNeeded()
self.view.layoutIfNeeded()
})
可以通过这种方式在 keyboardDidShowNotification 上计算精确的重叠
let parentRelativeFrame = view.convert(view.frame, to: nil)
let viewBottomVerticalOffset = parentRelativeFrame.origin.y + parentRelativeFrame.height
let overlap = viewBottomVerticalOffset - keyboardFrame.origin.y
我需要在显示键盘时调整 'message bar',并且在使用 iPad 模态视图控制器时遇到问题。 'message bar' 在显示时应该位于键盘的正上方,然后在隐藏键盘时位于模式的底部(消息应用程序样式)。
问题是我需要根据 Modal 的坐标系获取键盘框架的最高点。 我发现这个答案在理论上似乎是正确的,但不起作用 (How can I find portion of my view which isn't covered by the keyboard (UIModalPresenationStyleFormSheet)?):
仅供参考当显示键盘时,主要 window 中的键盘框架(即 'keyboardFrame')= (-84.0, 526.0, 768.0, 264.0)。为模态视图控制器坐标系(即 'newSize')转换时的键盘框架 = (-168.0, 292.0, 768.0, 264.0)*
// Convert the keyboard rect into the view controller's coordinate system
// The fromView: nil means keyboardRect is in the main window's coordinate system
let newSize = self.view.convertRect(keyboardFrame, fromView: nil)
// And then this is the part that gets covered!
let keyboardCoveredHeight = self.view.bounds.height - newSize.origin.y
self.messageToolbar.bottomConstraint.constant = -keyboardCoveredHeight
我认为您 运行 遇到了以下两个问题之一(也许两者都有):
- 在iOS8中,你必须将键盘的矩形从屏幕的坐标转换为space
- 在 iPad 上,sheet 视图有时会在显示键盘时向上移动一点,这发生在 键盘显示之后,因此您需要在
viewWillLayoutSubviews
中再次计算结果
这里是a sample project that does what you want。
为了后代,这里是有趣的源代码:
class TypingViewController: UIViewController {
var keyboardHoverView: UIView! // your keyboard toolbar or whatever
var lastKeyboardFrame : CGRect! // whenever you get a frame update, store it here
override func viewDidLoad() {
super.viewDidLoad()
createKeyboardHoverView()
observeKeyboard()
}
func createKeyboardHoverView() {
// make your keyboard toolbar
keyboardHoverView = view
}
func observeKeyboard() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification : NSNotification) {
let dict = notification.userInfo!
let frameValue = dict[UIKeyboardFrameEndUserInfoKey] as! NSValue
lastKeyboardFrame = frameValue.CGRectValue()
moveKeyboardView()
}
func keyboardWillHide(notification : NSNotification) {
moveKeyboardView()
}
override func viewWillLayoutSubviews() {
// this moves the view again, in case the modal view has shifted up
moveKeyboardView()
}
func moveKeyboardView() {
if lastKeyboardFrame != nil {
// this conversion is used in iOS 8 and differs from most online tutorials
let frameInThisView = self.view.convertRect(lastKeyboardFrame, fromCoordinateSpace: view.window!.screen.coordinateSpace)
var newRect = keyboardHoverView.frame
newRect.origin.y = frameInThisView.origin.y - CGRectGetHeight(newRect)
keyboardHoverView.frame = newRect
println("Setting rect: \(newRect)")
}
}
}
我最终使用熟悉的类别在 iPad 模态视图中获得正确的键盘框架:
- (CGFloat)heightCoveredByKeyboardOfSize:(CGSize)keyboardSize
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
CGRect frameInWindow = [self convertRect:self.bounds toView:nil];
CGRect windowBounds = self.window.bounds;
CGFloat keyboardTop;
CGFloat heightCoveredByKeyboard;
//Determine height of the view covered by the keyboard relative to current rotation
switch (orientation)
{
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
keyboardTop = windowBounds.size.height - keyboardSize.height;
heightCoveredByKeyboard = windowBounds.size.height - frameInWindow.origin.y - keyboardTop;
break;
case UIInterfaceOrientationPortraitUpsideDown:
default:
keyboardTop = windowBounds.size.height - keyboardSize.height;
heightCoveredByKeyboard = CGRectGetMaxY(frameInWindow) - keyboardTop;
break;
}
return MAX(0.0f,heightCoveredByKeyboard);
}
连同 DAKeyboardControl(用于平移):
// Use [unowned self] in closure for weak reference
self.view.addKeyboardPanningWithFrameBasedActionHandler(nil, constraintBasedActionHandler: { [unowned self] (keyboardFrameInView, opening, closing) -> Void in
if opening
{
if UIDevice.isIpad()
{
// iPad requires a different method due to use of modal view
self.messageToolbar.bottomConstraint.constant = -self.view.heightCoveredByKeyboardOfSize(keyboardFrameInView.size)
}
else
{
self.messageToolbar.bottomConstraint.constant = -keyboardFrameInView.size.height
}
}
if closing
{
self.messageToolbar.bottomConstraint.constant = 0
}
self.view.updateConstraintsIfNeeded()
self.view.layoutIfNeeded()
})
可以通过这种方式在 keyboardDidShowNotification 上计算精确的重叠
let parentRelativeFrame = view.convert(view.frame, to: nil)
let viewBottomVerticalOffset = parentRelativeFrame.origin.y + parentRelativeFrame.height
let overlap = viewBottomVerticalOffset - keyboardFrame.origin.y