-
Notifications
You must be signed in to change notification settings - Fork 59
Usage
This page will describe how to use RMActionController in your project.
RMActionController does not come with any content view (the one in the middle between all those buttons) for presentation. This means presenting an RMActionController only presents a set of buttons. For this task UIAlertController might be a better option.
The strength of RMActionController is that it can present any UIView as content view in an UIActionSheet/UIAlertController like fashion. To add a content view to RMActionController it is usually subclassed. This project contains two subclasses (RMCustomViewActionController and RMMapActionController) which give two examples for a subclass of RMActionController. In addition, you might want to take a look at the following projects for more examples on how to use RMActionController:
- RMDateSelectionViewController: Presents a UIDatePicker in an UIActionSheet/UIAlertController like manner.
- RMPickerViewController: Presents a UIPickerView in an UIActionSheet/UIAlertController like manner.
The remainder of this wiki page will explain how to create a subclass of RMActionController.
First create your own subclass of RMActionController. I assume you know how to do that. When creating your subclass you can specify a generic type. This type should be set to the class of the content view you are about to show. For example, if you are planning to present an MKMapView, the generic should be set to MKMapView. However, the generic type must be UIView or a subtype of UIView.
@interface RMMapActionController : RMActionController<MKMapView *>
@end
class MapActionController: RMActionController<MKMapView> {
}
When subclassing RMActionController you only have to overwrite one method. This method is called actionControllerWithStyle:title:message:selectAction:andCancelAction:
. For example, if you want to present an MKMapView your implementation may look like follows:
- (instancetype)initWithStyle:(RMActionControllerStyle)aStyle title:(NSString *)aTitle message:(NSString *)aMessage selectAction:(RMAction *)selectAction andCancelAction:(RMAction *)cancelAction {
self = [super initWithStyle:aStyle title:aTitle message:aMessage selectAction:selectAction andCancelAction:cancelAction];
if(self) {
self.contentView = [[MKMapView alloc] initWithFrame:CGRectZero];
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *bindings = @{@"mapView": self.contentView};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[mapView(>=300)]" options:0 metrics:nil views:bindings]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[mapView(200)]" options:0 metrics:nil views:bindings]];
}
return self;
}
required override init(style aStyle: RMActionControllerStyle, title aTitle: String?, message aMessage: String?, select selectAction: RMAction<MKMapView>?, andCancel cancelAction: RMAction<MKMapView>?) {
super.init(style: aStyle, title: aTitle, message: aMessage, select: selectAction, andCancel: cancelAction);
self.contentView = MKMapView(frame: .zero)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
let bindings = ["contentView": self.contentView];
self.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "[contentView(>=300)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: bindings))
self.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[contentView(200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: bindings))
}
Please make sure to set the contentView property of RMActionController to the content view you want to show. This property will be the only way for you to access the content view in any callbacks. Also, if the contentView is not set RMActionController will throw an exception when presenting.
If you are using Swift you also need to to overwrite the initializer for NSCoder.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
}
Sometimes you need to disable the blurred background for the content view you want to show (for example, this is the case for presenting an MKMapView). If you encounter such a case you need to overwrite the getter of the property disableBlurEffectsForContentView and always return true.
- (BOOL)disableBlurEffectsForContentView {
return YES;
}
override var disableBlurEffectsForContentView:Bool {
get {
return true;
}
set {
}
}
Presenting your subclass of RMActionController works by using standard Apple API.
- (IBAction)openActionController:(id)sender {
RMAction *selectAction = [RMAction<MKMapView *> actionWithTitle:@"Select" style:RMActionStyleDone andHandler:^(RMActionController<MKMapView *> *controller) {
NSLog(@"Action controller selected location: %f, %f", controller.contentView.centerCoordinate.latitude, controller.contentView.centerCoordinate.longitude);
}];
RMAction *cancelAction = [RMAction<MKMapView *> actionWithTitle:@"Cancel" style:RMActionStyleCancel andHandler:^(RMActionController<MKMapView *> *controller) {
NSLog(@"Action controller was canceled");
}];
RMMapActionController *actionController = [RMMapActionController actionControllerWithStyle:RMActionControllerStyleWhite title:@"Test" message:@"This is a map action controller.\nPlease select a location and tap 'Select' or 'Cancel'." selectAction:selectAction andCancelAction:cancelAction];
//Now just present the action controller using the standard iOS presentation method
[self presentViewController:actionController animated:YES completion:nil];
}
func openMapActionController() {
let selectAction = RMAction<MKMapView>(title: "Select", style: RMActionStyle.done) { controller in
print("Action controller selected location: ", controller.contentView.centerCoordinate.latitude, controller.contentView.centerCoordinate.longitude)
}
let cancelAction = RMAction<MKMapView>(title: "Cancel", style: RMActionStyle.cancel) { _ in
print("Map action controller was canceled")
}
let actionController = MapActionController(style: .white, title: "Test", message: "This is a map action controller.\nPlease choose a date and press 'Select' or 'Cancel'.", select: selectAction, andCancel: cancelAction)
//Now just present the action controller using the standard iOS presentation method
present(actionController, animated: true, completion: nil)
}
There are some options you might want to set before presenting your subclass of RMActionController:
-
disableBouncingEffects
: Enables/Disables any bouncing effect when presenting your subclass of RMActionController. -
disableMotionEffects
: Enables/Disables any motion effect when tilting your device while your subclass of RMActionController is being presented. -
disableBlurEffects
: Enables/Disables any blur effect when presenting your subclass of RMActionController. The background of RMActionController will not be blurred when disabled.
In addition, RMActionController is a UIViewController. Therefore you can also set any property of UIViewController which might be necessary for presenting. For example, you might want to set the modal presentation style for adapting your subclass of RMActionController to the iPad. This might look as follows:
- (IBAction)openMapActionController:(id)sender {
// Code as shown above
...
//First we set the modal presentation style to the popover style
actionController.modalPresentationStyle = UIModalPresentationPopover;
//Then we tell the popover presentation controller, where the popover should appear
actionController.popoverPresentationController.sourceView = self.tableView;
actionController.popoverPresentationController.sourceRect = CGRectMake(...);
//Now just present the action controller using the standard iOS presentation method
[self presentViewController:actionController animated:YES completion:nil];
}
func openMapActionController() {
// Code as shown above
...
//First we set the modal presentation style to the popover style
actionController.modalPresentationStyle = UIModalPresentationStyle.popover
//Then we tell the popover presentation controller, where the popover should appear
if let popoverPresentationController = actionController.popoverPresentationController {
popoverPresentationController.sourceView = self.tableView
popoverPresentationController.sourceRect = CGRect(...)
}
//Now just present the action controller using the standard iOS presentation method
present(actionController, animated: true, completion: nil)
}
You may use RMActionController in both your main application and your action extension showing an user interface. RMActionController only uses APIs that are safe to be used in extensions, too.