iPhone X How to Handle View Controller Inputaccessoryview

iPhone X how to handle View Controller inputAccessoryView?

inputAccessoryView and safe area on iPhone X

  • when the keyboard is not visible, the inputAccessoryView is pinned on the very bottom of the screen. There is no way around that and I think this is intended behavior.

  • the layoutMarginsGuide (iOS 9+) and safeAreaLayoutGuide (iOS 11) properties of the view set as inputAccessoryView both respect the safe area, i.e on iPhone X :

    • when the keyboard is not visible, the bottomAnchor accounts for the home button area
    • when the keyboard is shown, the bottomAnchor is at the bottom of the inputAccessoryView, so that it leaves no useless space above the keyboard

Working example :

import UIKit

class ViewController: UIViewController {

override var canBecomeFirstResponder: Bool { return true }

var _inputAccessoryView: UIView!

override var inputAccessoryView: UIView? {

if _inputAccessoryView == nil {

_inputAccessoryView = CustomView()
_inputAccessoryView.backgroundColor = UIColor.groupTableViewBackground

let textField = UITextField()
textField.borderStyle = .roundedRect

_inputAccessoryView.addSubview(textField)

_inputAccessoryView.autoresizingMask = .flexibleHeight

textField.translatesAutoresizingMaskIntoConstraints = false

textField.leadingAnchor.constraint(
equalTo: _inputAccessoryView.leadingAnchor,
constant: 8
).isActive = true

textField.trailingAnchor.constraint(
equalTo: _inputAccessoryView.trailingAnchor,
constant: -8
).isActive = true

textField.topAnchor.constraint(
equalTo: _inputAccessoryView.topAnchor,
constant: 8
).isActive = true

// this is the important part :

textField.bottomAnchor.constraint(
equalTo: _inputAccessoryView.layoutMarginsGuide.bottomAnchor,
constant: -8
).isActive = true
}

return _inputAccessoryView
}

override func loadView() {

let tableView = UITableView()
tableView.keyboardDismissMode = .interactive

view = tableView
}
}

class CustomView: UIView {

// this is needed so that the inputAccesoryView is properly sized from the auto layout constraints
// actual value is not important

override var intrinsicContentSize: CGSize {
return CGSize.zero
}
}

See the result here

How can I show the inputAccessoryView in this view controller

Your CommentsLauncher never become the first responder in the code you provided. A UIResponder's inputAccessoryView is displayed when the responder becomes first responder.

Change your showLauncher method to something like this:

func showLauncher() {
if let window = UIApplication.shared.keyWindow {
window.addSubview(view)
becomeFirstResponder()
}
}

And you should see the input accessory view.

Leaving inputAccessoryView visible after keyboard is dismissed

It's done like this:

Assign your UIToolbar to a property in your view controller:

@property (strong, nonatomic) UIToolbar *inputAccessoryToolbar;

In your top view controller, add these methods:

- (BOOL)canBecomeFirstResponder{

return YES;

}

- (UIView *)inputAccessoryView{

return self.inputAccessoryToolbar;

}

And then (optionally, as it usually shouldn't be necessary), whenever the keyboard gets hidden, just call:

[self becomeFirstResponder];

That way, your inputAccessoryToolbar will be both your view controller's and your text view's input accessory view.

iPhone: How to fix inputAccessoryView to View?

I solved this by listening for Notifications and moving the toolbar up... oh well.

Something like this does the job:

- (void)viewWillAppear:(BOOL)animated 
{
[super viewWillAppear:animated];
/* Listen for keyboard */
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
[keyboardToolbar setItems:itemSetFull animated:YES];
/* Move the toolbar to above the keyboard */
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect frame = self.keyboardToolbar.frame;
frame.origin.y = self.view.frame.size.height - 210.0;
self.keyboardToolbar.frame = frame;
[UIView commitAnimations];
}

- (void)keyboardWillHide:(NSNotification *)notification
{
[keyboardToolbar setItems:itemSetSmall animated:YES];
/* Move the toolbar back to bottom of the screen */
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect frame = self.keyboardToolbar.frame;
frame.origin.y = self.view.frame.size.height - frame.size.height;
self.keyboardToolbar.frame = frame;
[UIView commitAnimations];
}

I guess input accessory view is literally just meant for something stuck on top of the keyboard :)

autoResizingMask for inputAccessoryView not working

Unlike for table view cells, there is no support for dynamic height calculation in input accessory views, as far as I know.

You could use a fixed height for the accessory view.

But I assume, that you want just to change either top, bottom, or height constraint in interface builder and the change is reflected after the next build.

What you could do is, to use a custom view class where you connect your top, bottom and height constraints.

Then override intrinsicContentSize and return the sum of the three constraint constants.

class TextFieldContainer: UIView {

@IBOutlet weak var topConstraint: NSLayoutConstraint!
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
@IBOutlet weak var heightConstraint: NSLayoutConstraint!

override var intrinsicContentSize: CGSize {

let contentHeight =
self.topConstraint.constant
+ self.heightConstraint.constant
+ self.bottomConstraint.constant

return CGSize(width: UIScreen.main.bounds.width, height: contentHeight)
}
}

Your layout hierarchy could be simplified and look like this:

view layout

The autoresizing mask could look like this:

autoresizing mask

The final result would behave like the following then:

input accessory view



Related Topics



Leave a reply



Submit