iPhone X how to handle View Controller inputAccess

2019-01-11 01:46发布

I have a messaging app that has the typical UI design of a text field at the bottom of a full screen table view. I am setting that text field to be the view controller's inputAccessoryView and calling ViewController.becomeFirstResponder() in order to get the field to show at the bottom of the screen.

I understand this is the Apple recommended way of accomplishing this UI structure and it works perfectly on "classic" devices however when I test on the iPhone X simulator I notice that using this approach, the text field does not respect the new "safe areas". The text field is rendered at the very bottom of the screen underneath the home screen indicator.

I have looked around the the HIG documents but haven't found anything useful regarding the inputAccessoryView on a view controller.

It's difficult because using this approach I'm not actually in control of any of the constraints directly, I'm just setting the inputAccessoryView and letting the view controller handle the UI from there. So I can't just constrain the field to the new safe areas.

Has anyone found good documentation on this or know of an alternate approach that works well on the iPhone X?

enter image description here

12条回答
Anthone
2楼-- · 2019-01-11 02:04

Seems it's an iOS bug, and there is a rdar issue for it: inputAccessoryViews should respect safe area inset with external keyboard on iPhone X

I guess this should be fixed in iOS update when iPhone X will come up.

查看更多
劳资没心,怎么记你
3楼-- · 2019-01-11 02:04

Until safe are insets are guided by iOS automatically, simple workaround would be to wrap your accessory in container view and set bottom space constraint between accesory view and container view to match safe area insets of window.

Note: Of course this workaround can double your accessory view spacing from bottom when iOS update fixes bottom spacing for accessory views.

E.g.

- (void) didMoveToWindow {
    [super didMoveToWindow];
    if (@available(iOS 11.0, *)) {
        self.bottomSpaceConstraint.constant = self.window.safeAreaInsets.bottom;
    }
}
查看更多
小情绪 Triste *
4楼-- · 2019-01-11 02:09

-- For those who are using the JSQMessagesViewController lib --

I am proposing a fixed fork based on the JSQ latest develop branch commit.

It is using the didMoveToWindow solution (from @jki I believe?). Not ideal but worth to try while waiting for Apple's answer about inputAccessoryView's safe area layout guide attachment, or any other better fix.

You can add this to your Podfile, replacing the previous JSQ line:

pod 'JSQMessagesViewController', :git => 'https://github.com/Tulleb/JSQMessagesViewController.git', :branch => 'develop', :inhibit_warnings => true
查看更多
祖国的老花朵
5楼-- · 2019-01-11 02:11

I just created a quick CocoaPod called SafeAreaInputAccessoryViewWrapperView to fix this. It also dynamically sets the wrapped view's height using autolayout constraints so you don't have to manually set the frame. Supports iOS 9+.

Here's how to use it:

  1. Wrap any UIView/UIButton/UILabel/etc using SafeAreaInputAccessoryViewWrapperView(for:):

    SafeAreaInputAccessoryViewWrapperView(for: button)
    
  2. Store a reference to this somewhere in your class:

    let button = UIButton(type: .system)
    
    lazy var wrappedButton: SafeAreaInputAccessoryViewWrapperView = {
        return SafeAreaInputAccessoryViewWrapperView(for: button)
    }()
    
  3. Return the reference in inputAccessoryView:

    override var inputAccessoryView: UIView? {
        return wrappedButton
    }
    
  4. (Optional) Always show the inputAccessoryView, even when the keyboard is closed:

    override var canBecomeFirstResponder: Bool {
        return true
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        becomeFirstResponder()
    }
    

Good luck!

查看更多
可以哭但决不认输i
6楼-- · 2019-01-11 02:11

I'm just add safe area to inputAccessoryView (checkbox at Xcode). And change bottom space constraint equal to bottom of safe area instead of inputAccessoryView root view bottom.

Constraint

And result

查看更多
够拽才男人
7楼-- · 2019-01-11 02:14

In the case you already have a custom view loaded via nib file.

Add a convenience constructor like this:

convenience init() {
    self.init(frame: .zero)
    autoresizingMask = .flexibleHeight
}

and override intrinsicContentSize:

override var intrinsicContentSize: CGSize {
    return .zero
}

In the nib set the first bottom constraint (of views that should stay above the safe area) to safeArea and the second one to superview with lower priority so it can be satisfied on older iOS.

查看更多
登录 后发表回答