The built-in AWFMapOptionsViewController
provides a quick and easy way to control the map layers and various options for an AWFWeatherMap
instance. However, you may want to provide a custom map options view within your own applications instead of the built-in version.
The basic approach is to use an UITableView
to display the available options, which can then be divided into sections as needed based on any particular grouping of options. This is what the built-in AWFMapOptionsViewController
automatically does for you.
The following is a basic implementation of setting up a custom map options view using a UITableView
, which can then be customized further using custom UITableViewCell
instances as required by your application. Since the example below posts a notification when weather layers are ready to be added and/or removed based on the option selections, you'll need to observe this notification where appropriate so you can then add and remove the layers on your weather map instance.
#import <UIKit/UIKit.h>
#import <AerisMapKit/AerisMapKit.h>
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT NSString * const MapLayersDidChange;
@interface MapOptionsViewController : UIViewController
@property (nonatomic, readonly) UITableView *tableView;
// currently active layers on the map, set before this controller is presented
@property (nonatomic, strong) NSArray<AWFMapLayer> *activeLayers;
@end
NS_ASSUME_NONNULL_END
#import "MapOptionsViewController.h"
@interface MapOptionsViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
// array to store the supported layer options to display in the table view
@property (nonatomic, strong) NSArray *layerOptions;
// keep track of layer selection/deselection so we know what needs to be added/removed
// when this controller is dismissed
@property (nonatomic, strong) NSMutableArray *layersToAdd;
@property (nonatomic, strong) NSMutableArray *layersToRemove;
@end
NSString * const MapLayersDidChange = @"MapLayersDidChange";
@implementation MapOptionsViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
tableView.allowsMultipleSelection = YES;
tableView.dataSource = self;
tableView.delegate = self;
tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self.view addSubview:tableView];
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"LayerCell"];
self.tableView = tableView;
// array of layer options to display in the table view
self.layerOptions = @[AWFMapLayerRadar, AWFMapLayerAdvisories];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] postNotificationName:MapLayersDidChange object:self userInfo:@{ @"add": self.layersToAdd, @"remove": self.layersToRemove }];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.layerOptions count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LayerCell"];
AWFMapLayer layer = self.layerOptions[indexPath.row];
BOOL selected = [self isLayerTypeActive:layer];
cell.textLabel.text = [AWFWeatherLayer nameForLayerType:layer];
if (selected) {
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
} else {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
AWFMapLayer layer = self.layerOptions[indexPath.row];
if ([self.layersToAdd containsObject:layer] == NO) {
[self.layersToAdd addObject:layer];
}
[tableView reloadData];
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
AWFMapLayer layer = self.layerOptions[indexPath.row];
if ([self.layersToAdd containsObject:layer]) {
[self.layersToAdd removeObject:layer];
}
if ([self.layersToRemove containsObject:layer] == NO) {
[self.layersToRemove addObject:layer];
}
[tableView reloadData];
}
#pragma mark - Private Methods
- (BOOL)isLayerTypeActive:(AWFMapLayer)layerType {
return ([self.activeLayers containsObject:layerType] && ![self.layersToRemove containsObject:layerType]) || [self.layersToAdd containsObject:layerType];
}
@end
import UIKit
import AerisMapKit
class MapOptionsViewController: UIViewController {
static let LayersDidChange = NSNotification.Name("MapLayersDidChange")
let tableView = UITableView()
// array to store the supported layer options to display in the table view
var layerOptions = [AWFMapLayer]()
// currently active layers on the map, set before this controller is presented
var activeLayers = [AWFMapLayer]()
// keep track of layer selection/deselection so we know what needs to be added/removed
// when this controller is dismissed
var layersToAdd = [AWFMapLayer]()
var layersToRemove = [AWFMapLayer]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "LayerCell")
view.addSubview(tableView)
NSLayoutConstraint.activate([tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
// array of layer options to display in the table view
layerOptions = [.radar, .advisories]
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.post(name: MapOptionsViewController.LayersDidChange, object: self, userInfo: ["add": layersToAdd, "remove": layersToRemove])
}
fileprivate func isLayerActive(layer: AWFMapLayer) -> Bool {
return (activeLayers.contains(layer) && layersToRemove.contains(layer) == false) || layersToAdd.contains(layer)
}
}
extension MapOptionsViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return layerOptions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LayerCell", for: indexPath)
let layer = layerOptions[indexPath.row]
let selected = isLayerActive(layer: layer)
cell.textLabel?.text = AWFWeatherLayer.name(forLayerType: layer)
if selected {
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
} else {
tableView.deselectRow(at: indexPath, animated: false)
}
return cell
}
}
extension MapOptionsViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let layer = layerOptions[indexPath.row]
if !layersToAdd.contains(layer) {
layersToAdd.append(layer)
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let layer = layerOptions[indexPath.row]
if let index = layersToRemove.index(of: layer) {
layersToRemove.remove(at: index)
}
}
}
Last modified: May 21, 2020