I'm trying to figure out how to display a UIAlertController
with a style of UIAlertControllerStyleActionSheet
within my iMessage app extension.
The problem is, the action sheet appears below the native iMessage text field when presented when calling:
[self.view.window.rootViewController presentViewController:actionSheetController animated:YES completion:NULL];
How would I go about fixing this?
Code:
UIAlertController *actionSheetController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Clear", nil) message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *clear = [UIAlertAction actionWithTitle:NSLocalizedString(@"Clear", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action)
{
[self clear];
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action)
{}];
[actionSheetController addAction:clear];
[actionSheetController addAction:cancel];
[self.view.window.rootViewController presentViewController:actionSheetController animated:YES completion:NULL];
Here is a workaround. Maybe add a little animation to make it smooth.
[self.view.window.rootViewController presentViewController:actionSheetController animated:YES completion:^{
actionSheetController.view.frame = CGRectOffset(actionSheetController.view.frame, 0, -40);
}];
Another workaround:
actionSheetController.view.transform = CGAffineTransform(translationX: 0, y: -40)
[self.view.window.rootViewController presentViewController:actionSheetController animated:YES completion:NULL];
Do not hardcode the y-position for the action sheet.
This could lead to ui issues on later iOS major updates, when apple changes the height of the iMessage dock. Instead use the safeAreaInsets.bottom
value in order to find out by which value the view is hidden by the dock.
Here is the solution we are using:
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
actionSheet.dismiss(animated: true, completion: nil)
}))
// Adding further actions...
present(actionSheet, animated: true) {
UIView.animate(withDuration: 0.2, animations: {
actionSheet.view.frame = CGRect(x: actionSheet.view.frame.minX,
y: actionSheet.view.frame.minY - self.view.safeAreaInsets.bottom,
width: actionSheet.view.frame.width,
height: actionSheet.view.frame.height)
})
}
Detail: The action sheet is hidden by the iMessage dock, because the view controllers view over which you are presenting the action sheet is tied up to the bottom of the view and not the top of the iMessage dock. This case must be considered e.g. when adding constraints to other views and its subview.
Update:
Just use the following code in order to avoid the animation above. In my case after time seeing the animation did get pretty annoying.
extension UIAlertController {
open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard let viewController = presentingViewController else { return }
view.transform = .identity
view.transform = .init(translationX: 0.0, y: - viewController.view.safeAreaInsets.bottom)
}
}
according to this, you can request full screen presentation by:
[self requestPresentationStyle:MSMessagesAppPresentationStyleExpanded];
before your code:
[self.view.window.rootViewController presentViewController:actionSheetController animated:YES completion:NULL];