Map view
Map Floorplan
Overview
Use SAP Fiori Map Floorplan to extend Apple’s MapKit and Esri’s ArcGIS frameworks. The floorplan supports native map APIs and adds additional components to enhance the map experience. Maps are built upon layers of geometries (points, polylines, and polygons). Floorplans provide foundation for functionality including, showing search results, geometry details, and geometry creation. Floorplans currently only support iPad devices.
Components

Display Geometries
Layers
The map view may consist of multiple display layers. Each layer is represented by an FUIGeometryLayer object, which has the displayName property. By assigning geometries to distinct layers, geometries can be organized by their business context and then consumed by the map display. The state or behavior of all geometries can then be easily controlled layer by layer. For example, developer can show or hide all geometries on a specified layer using setLayerHidden(_:hidden:) method.
- Initialization of
FUIGeometryLayers on map view
An FUIGeometryLayer object can be initialized by setting its displayName. In the example App, there are three geometry layers defined: special zones, NYC ferry, and NYC MTA.
enum Layer {
static let zones = FUIGeometryLayer(displayName: "Special Zones")
static let stops = FUIGeometryLayer(displayName: "NYC Ferry")
static let mtaStops = FUIGeometryLayer(displayName: "NYC MTA")
}
Display Objects
In the example App, we added annotations and overlays to the FUIMKMapView. By default FUIMKMapView has its own data source implementation and all added annotations and overlays will be automatically managed when calling reloadData().
- Add annotation objects to the internally managed map data source
Developer can add annotations to the data source of FUIMKMapView directly by calling reloadData(). In such way, the added annotations will also be automatically appended to the corresponding geometry layer. Below code snippet demonstrates adding an array of stop annotations to the data source.
var stopAnnotations: [MKPointAnnotation] = [] {
didSet {
reloadData()
}
}
- Add overlay objects to the internally managed map data source
Likewise, developer can add overlays to the data source of FUIMKMapView directly by calling reloadData(). In such way, the added overlays will also be automatically appended to the corresponding geometry layer. Below code snippet demonstrates adding an array of zone overlays to the data source.
var zonesOverlays: [MKPolygon] = [] {
didSet {
reloadData()
}
}
- Working with native
MKMapViewinstance methods
Developer may still use native MKMapView methods to manage annotations and overlays on the map view. Native methods like addAnnotation(_:), addOverlay(_:) works the same on FUIMKMapView. However, for annotation and overlay objects added without geometry layer information, they cannot be configured using methods specialized for wrapper display geometries.
Additionally, developer should manage the display of their own annotations and overlays objects. This can be achieved by implementing your own mapView:viewForAnnotation: and renderer(for:) delegate methods. Below code snippet demonstrates the implementation of custom annotation view for MTA stops.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
...
if mtaStopAnnotations.contains(pointAnnotation) {
let view = mapView.dequeueReusableAnnotationView(withIdentifier: "FUIMarkerAnnotationView", for: annotation) as! FUIMarkerAnnotationView
view.markerTintColor = UIColor.preferredFioriColor(forStyle: .map6)
view.glyphImage = FUIIconLibrary.map.marker.bus
view.clusteringIdentifier = nil
return view
} else if stopAnnotations.contains(pointAnnotation) {
return nil
} else if editAnnotations.contains(where: { return $0 as? MKPointAnnotation != nil }) {
let view = mapView.dequeueReusableAnnotationView(withIdentifier: "FUIMarkerAnnotationView", for: annotation) as! FUIMarkerAnnotationView
view.markerTintColor = UIColor.preferredFioriColor(forStyle: .map5)
view.glyphImage = FUIIconLibrary.map.marker.venue
view.clusteringIdentifier = nil
return view
}
return nil
}
Clustering
A clustering annotation groups two or more distinct annotations into a single entity. FUIMKMapView utilize the same mechanism from MapKit to generate clustered annotations. Depends on the global setting of property isClusteringEnabled on the floorplan view controller as well as the specific setting of property clusteringIdentifier for each annotation view, the map view automatically creates cluster annotations when two or more annotation views become grouped too closely together on the map surface.
In the example App, only stop annotations are set to enable clustering. For MTA stop annotations, clustering is disable. The screenshot below illustrates their different behavior.

By default, clustering is enable for your map view controller once it is inherited from FUIMapFloorplanViewController. Therefore, in default state all annotations added to the map view will be clustered automatically depending on the zoom level. Two ways of customizations on specific annotation view can be made on the map view:
- Determine if an annotation view should be clustered or not:
If clusteringIdentifier is set to nil, the annotation view will not be clustered. You may also define distinct clusteringIdentifier value for annotation views that should not be clustered. The settings of clusteringIdentifier is commonly done by implementing the delegate method mapView(_:viewFor:).
public func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
...
guard let _ = annotation as? FUIAnnotation else {
let view = mapView.dequeueReusableAnnotationView(withIdentifier: "FUIMarkerAnnotationView", for: annotation) as! FUIMarkerAnnotationView
view.markerTintColor = UIColor.preferredFioriColor(forStyle: .map6)
view.glyphImage = FUIIconLibrary.map.marker.bus
view.clusteringIdentifier = nil
return view
}
return nil
}
- Customize the cluster annotation:
To customize the cluster annotation for the specified set of annotations, implement the mapView(_:clusterAnnotationForMemberAnnotations:) method in your map’s delegate. This delegate will not be called if the clusteringIdentifier for the annotation view is set to nil.
Map Interactions
- Overlay Selection and Deselection
Native MapKit provides some handy property and methods to manage interaction with annotations: selectedAnnotations to get an array of selected annotations, selectAnnotation(_:animated:)
to select the specified annotation and displays a callout view for it, and deselectAnnotation(_:animated:) to
deselect the specified annotation and hides its callout view.
Likewise, FUIMKMapView provides equivalent property and methods to manage interaction with overlays:
selectedOverlays: get an array of selected overlays.selectOverlay(_:animated:): select the specified overlay and change its display to selected state.deselectOverlay(_:animated:): deselect the specified overlay and restore its display to default state.
- Map view delegate setting
Before using the overlay selection functionality, developer should make sure their own map view controller has been sub-classed from FUIMKMapFloorplanViewController. Also developer should set map view’s delegate to their own map view delegate implementation:
let mapDelegate = MKMapViewDelegateImpl()
mapView.delegate = mapDelegate
- Selection/Deselection behavior of overlay on map view
At this point, once the custom map view’s delegate is correctly set, the interaction with overlays through tap gesture is supported right out of box. Please note that at one time only one overlay object on map can be selected. Also if an annotation call out is highlighted, all other selected overlay reset to default state.
Overlay selection and deselection can also be implemented using the detail panel as below.

- Link selection behavior of overlay to detail panel
Detail panel is implemented by a table view. So to define the selection behavior from the detail panel, developer has to implement the tableView(_didSelectRowAt:) method for the detail panel.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
if let zone = feature.zone {
self.pushContent(for: zone)
}
...
}
After that, the pushContent(for:) method needs to be implemented to trigger the selection behavior for the overlay. Developer needs to get selected overlay through table view index value, and then initiate selectOverlay(_:animated:) to enable selection state on the overlay.
func pushContent(for zone: Feature<BetaNYC.Zone>) {
...
if let index = zonesFeatureCollection.features.firstIndex(where: { $0.properties.id == zone.properties.id }) {
self.mapView.selectOverlay(zonesOverlays[index], animated: true)
}
...
}
- Link deselection behavior of overlay to detail panel
Deselection behavior from detail panel may be implemented through the completion handler on the close button: detailPanel?.content.closeButton.didSelectHandler. Developer may get a list of selected overlays from the selectedOverlays property, and then initiate deselectOverlay(_:animated:) to unselect all.
self.detailPanel?.content.closeButton.didSelectHandler = { [unowned self] _ in
...
for selectedOverlay in self.mapView.selectedOverlays {
self.mapView.deselectOverlay(selectedOverlay, animated: true)
}
...
}
Map Components
Default Toolbar
The toolbar contains buttons for common map functionalities. By default the toolbar has button for presenting settings, showing user location, presenting a map legend, and showing all annotations. The view is anchored to the right top right side of the map.

Settings
The settingsController is a UIViewController for the developer to set additional configurations for his/her application. The controller is presented modally as a formsheet over the map. Tapping on the close button will dismiss the controller and return to the map. In the example project, the settings acts as a placeholder and does not serve a functional purpose.

- Settings Data Binding
Settings is set below in viewDidLoad():
// Components: Settings
self.settingsController = SettingsTableViewController.shared
User Location
This button zooms the map to center on the coordinates of the user’s location.

Privacy settings must be changed in the Info.plist file to request permission to track location. Modify the file by adding the Privacy – Location When In Use Usage Description key. Check if permissions have been authorized in the viewDidAppear(_:) method.
Legend
The legend shows additional information about the MKAnnotationViews, MKPolylines, and MKPolygons that appear on the map. The legend is presented as a table in a UIPopoverPresentationController. The popover itself is anchored to the legend button within the toolbar. In the example, legend information about the Ferry Stops & Special Zones is provided.

- Legend Items
The legend contains a list of FUIMapLegendItems. Items contain icon, line, or fillItem, to represent the MKAnnotationView, MKPolyline, or MKPolygon. In the example app the legend items are defined according to their layer. The icon and fillItem variants are shown.
enum Layer {
...
static var zonesLegendItem: FUIMapLegendItem = {
var item = FUIMapLegendItem(title: Layer.zones.displayName)
item.fillItem = FUIMapLegendFillItem()
item.fillItem?.backgroundColor = UIColor.preferredFioriColor(forStyle: .map1)
item.fillItem?.borderColor = UIColor.preferredFioriColor(forStyle: .map1)
return item
}()
static var stopsLegendItem: FUIMapLegendItem = {
var item = FUIMapLegendItem(title: Layer.stops.displayName)
let image = FUIAttributedImage(image: FUIIconLibrary.map.marker.bus.withRenderingMode(.alwaysTemplate))
image.tintColor = .white
item.icon = FUIMapLegendIcon(glyphImage: image) //FUIMapLegendIcon(glyphImage: image)
item.backgroundColor = UIColor.preferredFioriColor(forStyle: .map6)
return item
}()
}
- Legend Title
A title to the legend by accessing the headerTextView and settings it’s text. Titles are truncated after reaching the legend maximum width.
- Legend passthrough views
Passthrough views allow for the legend to remain open while tapping separate views. By default both the detailPanel and toolbar are passthrough views. Add additional passthrough views by appending to the list,
- Legend Data Binding
Legend configurations are set in viewDidLoad():
// Components: Legend
self.legend.headerTextView.text = "New York Legend"
self.legend.items = [Layer.zonesLegendItem, Layer.stopsLegendItem]
self.legend.passThroughViews.append(mapView)
Zoom Extents
This button zooms the map to the region containing all annotations.
Note
Zoom Extents does not include the user’s location

Detail Panel
The detailPanel is a view that shows searchResults of map features and additional details about map components. The panel resizes to fit its content based on the controllers preferredContentSize and is anchored to the top left of the map.
Search Results
The searchResults control allows the user to filter map information when typing in the searchbar.


- Enable Search
Search Results is enabled by setting the isSearchEnabled Boolean value.
SearchResultstableViewdataSource
Setting the dataSource to populates the searchResults tableView. The tableView can also be configured by registering cells, adding estimated row heights, and enabling automatic dimensions.
SearchResultstableViewdelegate
The developer can set the delegate to respond to events. In the example project, row selection will push the content controller. (See Content Section below)
SearchResultssearchbardelegate
The developer can set the delegate to respond to events. In the example project, row selection will push the content controller. (See Content Section below)
SearchResultsData Binding
In the example project, the ViewController implements the UITableViewDataSource, UITableViewDelegate, and UISearchBarDelegate.
class ViewController: FUIMKMapFloorplanViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, EditingGeometryProviding {
...
// MARK: UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int { ... }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { ... }
// MARK: UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { ... }
// MARK: UISearchBarDelegate
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { ... }
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { ... }
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { ... }
}
SearchResults configurations are set in the viewDidLoad().
// Components: Detail Panel - SearchResults
self.detailPanel.isSearchEnabled = true
self.detailPanel.searchResults.tableView.dataSource = self
self.detailPanel.searchResults.tableView.delegate = self
self.detailPanel.searchResults.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier)
self.detailPanel.searchResults.tableView.estimatedRowHeight = 60
self.detailPanel.searchResults.tableView.rowHeight = UITableView.automaticDimension
self.detailPanel.searchResults.searchBar.delegate = self
Content
The content control presents additional information about a map component (MKAnnotationView, MKPolyline, MKPolygon, etc.). This controller is presented and dismissed by using the pushChildViewController() and popChildViewController() API respectively.

- Content Headline and Subheadline
The headlineText provides the title of the content and the subheadlineText provides additional title information. The headline is unscrollable and will always remain visible while the subheadline will be hidden while scrolling. A didSelectTitleHandler is that is called when the headlineText is tapped.
- Content DataSource and Delegate
Configure the tableView and set the dataSource and delegate to the tableView similar to the searchResults.
- Content Present
Calling pushChildViewController() will transition the content into view. It is up to the developer to determine when to present the content. In the example project, the controller is presented when a tableView row is selected. Update the controller properties and reloadData immediately prior to calling pushChildViewController().
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
self.pushContent(for: stop)
}
func pushContent(for stop: Feature<TransitLand.Stop>) {
...
detailPanel.content.headlineText = stop.properties.name
detailPanel.content.subheadlineText = stop.properties.operators.first?.values.first
detailPanel.content.didSelectTitleHandler = {
print(self.detailPanel.content.headlineText)
}
detailPanel.content.tableView.reloadData()
detailPanel.pushChildViewController()
}
Only one `content` can be displayed at a time. To update a `contentViewController`, reload the table then resize the panel by calling the `fitToContent()` method.
- Content Dismiss
Calling popChildViewController() dismisses the content and returns to searchResults.
This controller has a closeButton intended to dismiss itself. The developer can make additional changes prior to calling popChildViewController().
- Content Data Binding
As stated in searchResults, example project’s ViewController already implements UITableViewDataSource and UITableViewDelegate
Initial content configurations are set in the viewDidLoad().
// Components: Detail Panel - Content
self.detailPanel.content.tableView.dataSource = self
self.detailPanel.content.tableView.delegate = self
self.detailPanel.content.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier)
self.detailPanel.content.tableView.register(FUIMapDetailTagObjectTableViewCell.self, forCellReuseIdentifier: FUIMapDetailTagObjectTableViewCell.reuseIdentifier)
self.detailPanel.content.tableView.estimatedRowHeight = 44
self.detailPanel.content.tableView.rowHeight = UITableView.automaticDimension
self.detailPanel.content.closeButton.didSelectHandler = { [unowned self] _ in
...
self.detailPanel.popChildViewController()
}
Editing
The floorplan provides an editing interface to add geometries. Users can draw directly onto the map or input addresses to create their shape (point, polyline, or polygon)

- Set Editable Floorplan
To allow editing of the panel set the isEditable property to true.
- Set Create Geometry Items
The developer chooses what types of items can be created and placed on the map. In the example project, the user can create items that appear in the legend.
Tapping the + right bar button presents a popover to select the create geometry item. Once selected, the view controller will transition to an editing state by setting all other annotations to disabled and uninteractable, showing editing toolbar buttons, and presenting the editing panel. In the example project, the item that can be created is an editLegendItem.
- Set Creation Results Controller
This controller is available for the user to make additional changes to the workorder. In the example project, a placeholder controller is provided but does not have additional functionality.
- Save the Geometry
The developer is responsible for updating the model with the returned geometry. Use the didSaveResults closure to update the model. The first argument is the editing shape and the second argument is the type of workorder created. This closure is called after tapping the save bar button item on the createGeometryResultsController.
The Floorplan sets geometry creation and editing in viewDidLoad().
// Components: Editing Panel
self.isEditable = true
self.editingPanel.createGeometryItems = [Layer.editLegendItem]
self.editingPanel.createGeometryResultsController = CreateGeometryResultsController(provider: self)
self.editingPanel.didSaveResults = { [unowned self] shape, createObject in
if let point = shape as? MKPointAnnotation {
self.editAnnotations.append(point)
} else if let polyline = shape as? MKPolyline {
self.editAnnotations.append(polyline)
} else if let polygon = shape as? MKPolygon {
self.editAnnotations.append(polygon)
}
}
Editing Toolbar
The editing toolbar shows buttons to assist in geometry creation.

User Location Button
When tapped, the map will zoom to the user’s location. This button has the same functionality as the Default Toolbar User Location Button.
Zoom Extents Button
When tapped, the map will zoom to show all map annotations. This button has the same functionality as the Default Toolbar Zoom Extents Button.
Add Button
When selected, tapping on the map will add points to the map.
Delete Button
When selected, tapping on points of the current editing shape will delete the points.
Undo Button
Add and delete actions can be undone by tapping on the undo button.
Redo Button
Undo actions can be redone by tapping on the redo button.
Branch Button
To create a branch off of a polyline or polygon, select the branch button.
Note
The branch button is disabled when creating a point and when the delete button is selected.
Editing Panel
The Editing Panel shows editing configurations while creating a geometry. A user can select the type of geometry to create (point, polyline, or polygon) as well as add addresses directly to the shape.

Geometry Segmented Control
A user can switch between the geometries (point, polyline, or polygon) by tapping on the segment.
Note
Switching from polyline or polygon to point geometries will clear the stored points. The user will be prompted with an alert if they choose to continue.
Clear All Button
A user can clear all points by tapping the clear all button. The user will be prompted with an alert if they wish to continue.
Add New Point Field
This field allows the user to add addresses directly to the editing shape. Tapping the field will launch the keyboard.
Save Button
The save button will prepare to commit the changes and launch a create results controller. (See Save Geometries)
Drawing Interaction
Tap on the + button to open the create geometry popover. The example project allows the user to create “Edit Annotations”. Tap the cell to start.

Select the polyline image to create a polyline.

When the add button is selected points are added when the map is tapped




To add a point on a segment, tap directly on the line.

To move the point, long press and drag on the point to a new location.

To delete a point first select the delete button. The add button will become deselected.

Tap on a point to delete.

To undo the delete, tap the undo button.

To redo the delete, tap the redo button.

To add a branch select the add button,

then select the branch button.

Select a point on the segment then tap away.


Edit Panel Interaction
A user can directly add an address by tapping the Add New Point field. This launches the keyboard and shows suggestions.

Typing into the field provides suggestions for addresses.

Selecting the cell adds the address to the model.

Cells can be rearranged by dragging the cell with the hamburger icon.

To delete a cell from the panel, tap the red circle to show the delete button.

Accept the prompt to delete the point.

Switching between geometries is possible by changing the segmented control. First a prompt will appear.

Accept the prompt to change to polygon.

Changing from a polyline or polygon to a point will delete all the points. This action cannot be undone!

Points can be wiped by tapping the clear all button. This action cannot be undone!

Cancel the alert and return to the editing line. Tap the save button in the panel to launch the create results page.

The user can tap the cancel button to return back to editing. Tap the save bar button item to return back to the map and the editing geometry will be saved.

-
The main view of
FUIMapFloorplanViewController.Declaration
Swift
@MainActor open class FUIMapFloorplanContentView : FUIBaseDrawingView, FUIMapFloorplanComponent -
A generic map floorplan view controller that supports creating new geometry, editing geometry and save geometry. In general, you do not subclass this class directly. Use
FUIMKMapFloorplanViewController(MapKit).Views Available in
FUIMapFloorplanViewController:detailPanel: Displays a resizing panel that holds the search controller, content controller, and edit controller. The panel resizes based on the presented controllerpreferredContentSize.toolbar: A view that contains toolbar buttons for easy access to common map functionalities. Default toolbar buttons are provided.legend: A view that showsmapAnnotationsand their title.settingsController: A controller presented as aformSheetover the map allowing for customization of the map.createGeometryResultsController: A controller presented when a geometry is saved. Allows for additional configuration before committing the geometry.
Variables Available in
FUIMapFloorplanViewController:isEditable: ABoolthat prepares the floorplan for editing.createGeometryItems: An array that displays work orders to create in editing mode. The contents are displayed in a table and on cell selection displays the editing panel.isCreatePointEnabled: ABoolthat enables editing of point geometries.isCreatePolylineEnabled: ABoolthat enables editing of polyline geometries.isCreatePolygonEnabled: ABoolthat enables editing of polygon geometries.
Usage
override func viewDidLoad() { detailPanel.search.tableView.dataSource = dataSource detailPanel.content.tableView.dataSource = dataSource legend.items = items settingsController = controller createGeometryResultsController = controller }Editing Interaction:
The floorplan supports editing to allow users to add geometries (points, polylines, and polygons) by drawing directly on the map.
A floorplan subclass can become editable by setting
isEditable. The view controller will transition to an editing state by setting all other annotations to disabled, showing editing toolbar buttons, and presenting the editing panel. The+right bar button presents a popover allowing the user to select a geometry.Once the panel is presented, a user can toggle between geometry types (points, polylines, and polygons) to edit. The user can draw directly on the map by tapping on screen. The editing tool bar buttons show how the user can interact with the map. When the add Button is selected, the user can tap to add points. When the delete button is selected, a user can tap a point to delete. Actions can be undone and redone with the undo and redo buttons. Lastly the branch button can extend a polyline or polygon. To edit existing points the user can use the long press gesture to drag points to new locations.
Alternatively, A user can edit existing points using the panel. The user can input directly an address and a list of suggestions will be presented. Tapping on a suggestion will add the point to the map. To delete, tap the red circle to show the red delete button. Tap delete to remove the point. Reordering points is done by dragging cells among each other.
To save, tap the save button. This will launch the developer’s
See morecreateGeometryResultsControllerwhere the user can make additional changes to the work order. Tapping the save right bar button dismisses the controller and exits the editing state. It is up to the developer to update his/her model with the saved geometry.Declaration
Swift
@MainActor open class FUIMapFloorplanViewController<InnerView, EditingGeometryWrapper, EditingTypes> : FUIBaseDrawingViewController<InnerView>, FUIMapFloorplanComponent where InnerView : FUIMapFloorplanContentView, EditingGeometryWrapper : FUIManageRepresentation, EditingTypes : FUIGeometryTypeWrapper -
A subclass of
MKMapViewis designed to be used with MapKit framework. You can useFUIMKMapViewto display map information and to manipulate the map contents from your application. TheFUIMKMapViewclass supports the ability to cache common map interface objects: annotations and overlays. NativeMKMapViewAPI methods are also available for developer use. It also adds the selection and deselection handlers for overlays.Usage
When configuring your map interface with
FUIMKMapView, all the added annotation and overlay objects and their corresponding display objects will be cached internally. Add annotation objects to the map viewfunc addAnnotation(_ annotation: MKAnnotation, toLayer layer: FUIGeometryLayer) {} func addAnnotation(_ annotation: MKAnnotation, geometryLayer layer: FUIGeometryLayer) {} func addAnnotations(_ annotations: [MKAnnotation], geometryLayer layer: FUIGeometryLayer) {}Add overlay objects to the map view
func addOverlays(_ overlays: [MKOverlay], level: MKOverlayLevel, geometryLayer layer: FUIGeometryLayer) {} func addOverlays(_ overlays: [MKOverlay], geometryLayer layer: FUIGeometryLayer) {}Respond to select/deselect overlay action
func selectOverlay(_ overlay: MKOverlay, animated: Bool) {} func deselectOverlay(_ overlay: MKOverlay, animated: Bool) {}Theming
See moreDeclaration
Swift
@MainActor open class FUIMKMapView : MKMapView -
The main view of
See moreFUIMKMapFloorplanViewControllerDeclaration
Swift
@MainActor open class FUIMKMapFloorplanContentView : FUIMapFloorplanContentView -
A subclass of
FUIMapFloorplanViewControllerdesigned to be used with MapKit framework. You can use it to display business objects(points, polylines, polygons) on the map view and view details by selecting a business object. It also supports clustering of point geometries.Usage
The map view consists of mutiple
FUIGeometryLayers. By assigning geometries onto different layers, you can show/hide all geometries on a specified layer using setLayerHidden(_:hidden:) api.- Implement
FUIMKMapViewDataSourcemethods.
In the floorplan controller viewDidLoad() set the datasource.
self.dataSource = dataSourcefunc numberOfLayers(in mapView: MKMapView) -> Int { return 1 } func mapView(_ mapView: MKMapView, layerAtIndex index: Int) -> FUIGeometryLayer { return FUIGeometryLayer("Functional Location") } func mapView(_ mapView: MKMapView, geometriesForLayer layer: FUIGeometryLayer) -> [MKAnnotation] { return polylines }You can also add annotations/overlays to a specified layer using FUIMKMapView’s
addAnnotation(_:geometryLayer:)andaddOverlays(_:geometryLayer:)APIs. Make sure you update you data model accordingly.Please Note: If you use MapKit’s native APIs to add annotations/overlays, the
FUIMKMapViewDelegateobject is not able to manage these objects.- Implement
MKMapViewDelegatemethods as needed.
Developer can supply custom annotation views. FUIMarkerAnnotationView is provided by the floorplan.
mapView.delegate = delegateopen func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { guard let pointAnnotation = annotation as? MKPointAnnotation else { return nil } guard let view = FUIMarkerAnnotationView(annotation: pointAnnotation, reuseIdentifier: "cell") else { return nil } view.glyphImage = FUIIconLibrary.map.marker.venue.withRenderingMode(.alwaysTemplate) view.priorityIcon = FUIIconLibrary.map.marker.veryHighPriority }FUIMKMapViewDelegateprovides more functionalities that you can make your app more powerful.
In the floorplan controller viewDidLoad() set the delegate.
self.delegate = delegateDetermine how annotation view/overlay renderer should appear. You can customize the view/render provided with fiori default styles.
func mapView(_ mapView: MKMapView, willRender overlay: MKOverlayRenderer, for geometryIndex: Int, in layer: FUIGeometryLayer, in state: FUIMapFloorplan.State) { guard let polylineRenderer = overlayRenderer as? MKPolylineRenderer else { return } polylineRenderer.strokeColor = UIColor.blue polylineRenderer.setNeedsDisplay() }Respond to select/deselect action
func mapView(_ mapView: MKMapView, didSelect annotation: MKAnnotation, for geometryIndex: Int, in layer: FUIGeometryLayer) {} func mapView(_ mapView: MKMapView, didSelect clusterAnnotation: MKClusterAnnotation, for geometryIndexesInLayers: [FUIGeometryLayer: [Int]]) {} func mapView(_ mapView: MKMapView, didSelect overlay: MKOverlay, for geometryIndex: Int, in layer: FUIGeometryLayer) {} func mapView(_ mapView: MKMapView, didSelect overlayRenderer: MKOverlayRenderer) {} func mapView(_ mapView: MKMapView, didDeselect annotation: MKAnnotation, for geometryIndex: Int, in layer: FUIGeometryLayer) {} func mapView(_ mapView: MKMapView, didDeselect clusterAnnotation: MKClusterAnnotation, for geometryIndexesInLayers: [FUIGeometryLayer: [Int]]) {} func mapView(_ mapView: MKMapView, didDeselect overlay: MKOverlay, for geometryIndex: Int, in layer: FUIGeometryLayer) {} func mapView(_ mapView: MKMapView, didDeselect overlayRenderer: MKOverlayRenderer) {}Theming
See moreDeclaration
Swift
@MainActor open class FUIMKMapFloorplanViewController : FUIMapFloorplanViewController<FUIMKMapFloorplanContentView, MKEditingGeometryWrapper, MKEditingTypes>, EditingGeometryProducing - Implement
-
A View that wraps the
FUIMapToolbarButtonin a vertical stack.- The
FUIMapToolbarholds a maximum of 6FUIMapToolbarButton. - Default variants of
FUIMapToolbarButtonexist within the SDK. See,FUIMapToolbarSettingsButton,FUIMapToolbarUserLocationButton,FUIMapToolbarZoomExtentButton, orFUIMapToolbarLegendButton - The
FUIMapToolbarcan be presented in either a dark or light variant. - The
FUIMapToolbarwill be pinned to the givenMKMapViewin the top right corner
Usage
See morevar toolbar = FUIMapToolbar(mapView: mapView) toolbar.backgroundColorScheme = .dark // defaults to `.light` let locationButton = FUIMapToolbarUserLocationButton(mapView: self.mapView) let zoomExtentsButton = FUIMapToolbarZoomExtentButton(mapView: self.mapView) toolbar.items = [locationButton, zoomExtentsButton]Declaration
Swift
@MainActor open class FUIMapToolbar : FUIDrawingView - The
-
FUIMapToolbarButtoninherits from the FUIButton class and appears within theFUIMapToolbar.- Height and width are both set to 44
- Images should be set to 28 by 28 icons. Icons will be centered within the button.
- didSelectHandler can be set to add custom functionality on tap
Usage:
let toolbar = FUIMapToolbar(mapView: self.mapView) let settingsButton = FUIMapToolbarButton() settingsButton.isPersistentSelection = true settingsButton.setImage(FUIIconLibrary.system.information.withRenderingMode(.alwaysTemplate), for: .normal) settingsButton.didSelectHandler = { [weak self] button in DispatchQueue.main.async { let settings = DevMapSettingsViewController() settings.dismissButton = button let navController = UINavigationController(rootViewController: settings) if !(UIDevice.current.userInterfaceIdiom == .phone) { settings.modalPresentationStyle = .formSheet navController.modalPresentationStyle = .formSheet self.present(navController, animated: true, completion: nil) } else { navController.modalPresentationStyle = .overFullScreen let dismissClosure: (() -> Void)? = { [weak self] in self.dismiss(animated: true, completion: nil) } settings.dismissClosure = dismissClosure self.present(navController, animated: true, completion: nil) } } } toolbar.items = [settingsButton]Notes
- Subclass the
FUIMapToolbarButtonfor custom variants
See
See provided default variants:FUIMapToolbarSettingsButton,FUIMapToolbarUserLocationButton,FUIMapToolbarZoomExtentButton, andFUIMapToolbarLegendButtonSee moreSee
SeeFUIMapToolbarSettingsButtondocumentation for supplementaryDevMapSettingsViewControllerclassDeclaration
Swift
@MainActor open class FUIMapToolbarButton : FUIButton -
A
UIViewControllercontaining a tableView ofFUIMapLegendItems. This controller is intended to be presented within aUIPopoverPresentationController. It calculates its preferred content size based on the tableView’s content height and tableView’s content width between a maximum and minimum value.Available in FUIMapLegend:
items: an array ofFUIMapLegendItemthat will be displayed in the tableView.
Declaration
Swift
@MainActor open class FUIResizablePopoverContainer : UIViewController -
FUIMapLegendextendsUIViewControllerto show the Map Legend.FUIMapLegendis presented in aUIPopoverViewon iPad and presented in aUIPresentationControlleron iPhoneAvailable in
FUIMapLegend:headerTextView: aTextViewintended to display a footnote text.passThroughViews: an array ofUIViewthat a user can interact with while popover is visible
Example Initialization and Configuration:
In view controller’s
viewDidLoadmethod:let toolbar = FUIMapToolbar(mapView: mapView) let legend = FUIMapLegend() legend.toolbarButton = FUIMapToolbarLegendButton() legend.headerTextView.text = "MapView Example Legend" legend.passThroughViews = [toolbar, mapView] var venueItem = FUIMapLegendItem(title: "Self Service") venueItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map1) let venueImage = FUIAttributedImage(image: FUIIconLibrary.map.marker.venue.withRenderingMode(.alwaysTemplate)) venueImage.tintColor = .white venueItem.icon = FUIMapLegendIcon(glyphImage: venueImage) var valetItem = FUIMapLegendItem(title: "Valet") valetItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map2) let valetImage = FUIAttributedImage(image: FUIIconLibrary.map.marker.walk.withRenderingMode(.alwaysTemplate)) valetImage.tintColor = .white valetItem.icon = FUIMapLegendIcon(glyphImage: valetImage) valetItem.line = FUIMapLegendLine(dashPattern: [10,8], dashPhase: 3.0) let highActivityRegion = FUIMapLegendFillItem() highActivityRegion.fillColor = UIColor.preferredFioriColor(forStyle: .map3) highActivityRegion.borderColor = UIColor.preferredFioriColor(forStyle: .map3) var highActivityRegionItem = FUIMapLegendItem(title: "High Activity Region") highActivityRegionItem.fillItem = highActivityRegion var highTrafficPathItem = FUIMapLegendItem(title: "High Traffic Path") highTrafficPathItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map4) highTrafficPathItem.line = FUIMapLegendLine(dashPattern: [2,2], dashPhase: 0.0) legend.items = [highActivityRegionItem, valetItem, venueItem, highTrafficPathItem] let legendHandler: ((FUIButton) -> Void)? = { [weak self] button in DispatchQueue.main.async { var dismissLegendAndRestoreCachedController = { [unowned self, unowned button] in self.dismiss(animated: true, completion: { button.isSelected = false }) } let presentNewLegendPhone = { self.present(legend, animated: true, completion: nil) } let presentNewLegendPad = { legend.setupPopoverAttributes(popOver: legend.popoverPresentationController!, sender: button) if self.presentedViewController == nil { self.present(legend, animated: false, completion: nil) } } guard button.isSelected else { dismissLegendAndRestoreCachedController() return } let presentNewClosure = UIDevice.current.userInterfaceIdiom == .phone ? presentNewLegendPhone : presentNewLegendPad guard let presentedController = UIDevice.current.userInterfaceIdiom == .phone ? self.presentedViewController : self.popoverPresentationController?.presentedViewController else { presentNewClosure() return } if presentedController == legend { dismissLegendAndRestoreCachedController() } else { self.dismiss(animated: true, completion: { presentNewClosure() }) } } } legend.toolbarButton?.didSelectHandler = legendHandler let locationButton = FUIMapToolbarUserLocationButton(mapView: self.mapView) toolbar.items = [legend.toolbarButton!, locationButton]theming
fdlFUIMapLegendContainer_headerTextView { font-color: @primary3; font-name: semiboldSystem; font-style: footnote; }notes
See moreSee
See implementation ofFUIMapLegendusing aFUIMapToolbarLegendButtonfor a complete implementation.Declaration
Swift
@MainActor open class FUIMapLegend : FUIResizablePopoverContainerextension FUIMapLegend: UIViewControllerTransitioningDelegateextension FUIMapLegend: UITableViewDelegateextension FUIMapLegend: UITableViewDataSource -
FUIMapLegendItemis a struct to represent an entry in the Map Legend. AFUIMapLegendItemcan be one of 4 types:- icon: An item with a circular icon
- iconLine: An item with a circular icon and line
- line: An item with a line
- fill: An item with a filled polygon
Available:
title: aStringthat describes theFUIMapLegendItemtype: aFUIMapLegendItemTypedesignated for the item.backgroundColor: aUIColordisplayed as a backgroundColor for the itemtintColor: aUIColordisplayed as a tintColor for the itemicon: aFUIMapLegendIconfor the designated item.line: aFUIMapLegendLinefor the designated item.fillItem: aFUIMapLegendFillItemfor the designated item.
Example Initialization and Configuration:
See more// Type: .icon var venueItem = FUIMapLegendItem(title: "Self Service") venueItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map1) let venueImage = FUIAttributedImage(image: FUIIconLibrary.map.marker.venue.withRenderingMode(.alwaysTemplate)) venueImage.tintColor = .white venueItem.icon = FUIMapLegendIcon(glyphImage: venueImage) var valetItem = FUIMapLegendItem(title: "Valet") valetItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map2) let valetImage = FUIAttributedImage(image: FUIIconLibrary.map.marker.walk.withRenderingMode(.alwaysTemplate)) valetImage.tintColor = .white valetItem.icon = FUIMapLegendIcon(glyphImage: valetImage) valetItem.line = FUIMapLegendLine(dashPattern: [10,8], dashPhase: 3.0) let highActivityRegion = FUIMapLegendFillItem() highActivityRegion.fillColor = UIColor.preferredFioriColor(forStyle: .map3) highActivityRegion.borderColor = UIColor.preferredFioriColor(forStyle: .map3) var highActivityRegionItem = FUIMapLegendItem(title: "High Activity Region") highActivityRegionItem.fillItem = highActivityRegion var highTrafficPathItem = FUIMapLegendItem(title: "High Traffic Path") highTrafficPathItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map4) highTrafficPathItem.line = FUIMapLegendLine(dashPattern: [2,2], dashPhase: 0.0) legend.items = [highActivityRegionItem, valetItem, venueItem, highTrafficPathItem]Declaration
Swift
public struct FUIMapLegendItem -
FUIMapLegendIconis a struct to represent an entry in the Map Legend that displays an item with a circular icon.Example Initialization and Configuration:
See morevar venueItem = FUIMapLegendItem(title: "Self Service") venueItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map1) let venueImage = FUIAttributedImage(image: FUIIconLibrary.map.marker.venue.withRenderingMode(.alwaysTemplate)) venueImage.tintColor = .white venueItem.icon = FUIMapLegendIcon(glyphImage: venueImage) var valetItem = FUIMapLegendItem(title: "Valet") valetItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map2) let valetImage = FUIAttributedImage(image: FUIIconLibrary.map.marker.walk.withRenderingMode(.alwaysTemplate)) valetImage.tintColor = .white valetItem.icon = FUIMapLegendIcon(glyphImage: valetImage) valetItem.line = FUIMapLegendLine(dashPattern: [10,8], dashPhase: 3.0) legend.items = [venueItem, valetItem]Declaration
Swift
public struct FUIMapLegendIcon -
FUIMapLegendFillItemis aUIViewthat presents a square view with a fill color and border color.Available in FUIMapLegendFillItem:
fillColor: aUIColorthat is the fill color of the square viewborderColor: aUIColorthat is the border color of the square view
Example Initialization and Configuration:
See morelet highActivityRegion = FUIMapLegendFillItem() highActivityRegion.fillColor = UIColor.preferredFioriColor(forStyle: .map3) highActivityRegion.borderColor = UIColor.preferredFioriColor(forStyle: .map3) var highActivityRegionItem = FUIMapLegendItem(title: "High Activity Region") highActivityRegionItem.fillItem = highActivityRegion legend.items = [highActivityRegionItem]Declaration
Swift
@MainActor public class FUIMapLegendFillItem : UIView -
FUIMapLegendLineis a struct to represent the line in the Map Legend. The color of the line is determined by the backgroundColor set by the item.Available in FUIMapLegendLine:
dashPattern: an array ofNSNumberobjects specifying the lenghts of line segmentsdashPhase: aCGFloatdescribing how far into the dash pattern the line starts
Example Initialization and Configuration:
See morevar valetItem = FUIMapLegendItem(title: "Valet") valetItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map2) let valetImage = FUIAttributedImage(image: FUIIconLibrary.map.marker.walk.withRenderingMode(.alwaysTemplate)) valetImage.tintColor = .white valetItem.icon = FUIMapLegendIcon(glyphImage: valetImage) valetItem.line = FUIMapLegendLine(dashPattern: [10,8], dashPhase: 3.0) var highTrafficPathItem = FUIMapLegendItem(title: "High Traffic Path") highTrafficPathItem.backgroundColor = UIColor.preferredFioriColor(forStyle: .map4) highTrafficPathItem.line = FUIMapLegendLine(dashPattern: [2,2], dashPhase: 0.0) legend.items = [valetItem, highTrafficPathItem]Declaration
Swift
public struct FUIMapLegendLine -
A View Controller component within the
FUIMapDetailPanelas thecontent. This controller shows additional details of a business object. It is up to the developer to set the tableView dataSource and delegate. Typically not used directly by developer.Available:
headlineText: AStringused as the header text inside the panel. The headline text can wrap up to two lines and truncates at the tail.subheadlineText: AStringused as the subheadline text inside the panel. The subheadline text gradually disappears while thetableViewscrolls.didSelectTitleHandler: An optional handler that can be set by the developer that is executed when theheadlineTextis tapped. If thedidSelectTitleHandleris not nil, theheadlineTexttext color is changed to show that it is tappable.
Usage:
See morelet content: FUIMapDetailPanelContentViewController = FUIMapDetailPanelContentViewController() content.headlineText = "Headline Text" content.subheadlineText = "Subheadline Text" content.didSelectTitleHandler = { print("didSelectTitleHandler called!") } content.tableView.delegate = delegate content.tableView.dataSource = dataSource content.tableView.register(FUIMapDetailBaseObjectTableViewCell.self, forCellReuseIdentifier: FUIMapDetailBaseObjectTableViewCell.reuseIdentifier) content.tableView.estimatedRowHeight = 100 content.tableView.rowHeight = UITableView.automaticDimensionDeclaration
Swift
@MainActor final public class FUIMapDetailPanelContentViewController : FUIMapDetailPanelViewController -
A View Controller component used in the
FUIMapDetailPanel. It is up to the developer to set the tableView dataSource and delegate. Typically not used directly by developer.Usage:
See morelet vc = FUIMapDetailPanelViewController() vc.tableView.delegate = delegate vc.tableView.dataSource = dataSourceDeclaration
Swift
@MainActor public class FUIMapDetailPanelViewController : UIViewController, FUIMapDetailPanelProtocol -
Searchbar component of
FUIMapDetailPanelSearchResultsViewController. It is up to the developer to set the search delegate.Usage
See morelet searchBar: FUIMapDetailPanelSearchBar = FUIMapDetailPanelSearchBar() searchBar.delegate = delegateDeclaration
Swift
@MainActor public class FUIMapDetailPanelSearchBar : FUISearchBar -
A View Controller component within the
FUIMapDetailPanelas thesearchResults. This controller shows a tableView with search results using a given searchBar. It is up to the developer to set the searchBar delegate, tableView datasource, and tableView delegate. Typically not used directly by developer.Available:
tableView: AUITableViewthat displays search results. Developer must set the tableView datasource and delegate.searchBar: AFUIMapDetailPanelSearchBarthat should filter data. Developer must set the searchBar delegate.preferredContentSize: ACGSizethat determines the size of theUIViewController. This variable drives the resizing capabilities of the view and must set correctly and properly updated.isApplyingBlurBackground: ABoolthat determines if thetableViewwill use its blurredBackground. Setting it to false will set the tableView to theUITableViewdefault values.isApplyingBlurBackgrounddefault value is true.searchBar: AFUIMapDetailPanelSearchBarused to filter data.
Usage:
See morelet search = FUIMapDetailPanelSearchResultsViewController() search.isApplyingBlurBackground = true search.tableView.dataSource = tableViewDataSource search.tableView.delegate = tableViewDelegate search.tableView.register(FUIMapDetailTagObjectTableViewCell.self, forCellReuseIdentifier: FUIMapDetailTagObjectTableViewCell.reuseIdentifier) search.searchBar.delegate = searchBarDelegateDeclaration
Swift
@MainActor public class FUIMapDetailPanelSearchResultsViewController : FUIMapDetailPanelViewController -
A View Component that wraps the
FUIMapDetailPanelSearchResultsViewControlleras thesearchResultsControllerand theFUIMapDetailPanelContentViewControlleras thecontent. Switching between the two view controllers should be driven by thepushChildViewControllerandpopChildViewControllermethods in the developer’smapView(_:didSelect:)andmapView(_:didDeselect:)methods.## iPhone The
searchResultsandcontentwill be presented on cards that can be swipe and panned to a bottom, middle, or top position.## iPad The view is placed in the top left corner of the iPad and will dynamically resize based on the
preferredContentSize. The view is pinned to the givenpinMapViewand will resize accordingly. ThefitToContentmethod must be called when reloading the table view.## Available:
passThroughViews: A[UIView]that contains the views that are interactable when the map legend is presented on iPad. This prevents the popover from being dismissed while interacting with views in this list (ex. aMKMapView).isApplyingBlurBackground: ABoolthat determines if the child views will have a blurred background.isSearchEnabled: A Boolean value to instantiate search.searchResults: AFUIMapDetailPanelSearchResultsViewControllerused for the search function. Manipulate itstableViewto show search results. The developer must set thedatasourceand delegate methods.content: AFUIMapDetailPanelContentViewControllerused for showing the details. The developer must set thedatasourceand delegate methods.
## Usage
container = FUIMapDetailPanel(parentViewController: self, mapView: mapView) favoritesData = Array(sampleData[3..<sampleData.count]) container.isSearchEnabled = true container.isApplyingBlurBackground = true container.search.tableView.dataSource = searchResultsDataSource container.search.tableView.delegate = searchResultsDelegate container.search.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier) container.search.searchBar.delegate = searchResultsDelegate container.content.headlineText = "VA Palo Alto Health Care Sys wraps to two lines..." container.content.didSelectTitleHandler = { print("Developer Select Handler Called!") } container.content.subheadlineText = "Medical Center" container.content.tableView.dataSource = contentDataSource container.content.tableView.delegate = contentDelegate container.content.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier) container.content.tableView.estimatedRowHeight = 100 container.content.tableView.rowHeight = UITableView.automaticDimensionManage presenting the controller on iPhone in
viewDidAppear(_:).DispatchQueue.main.async { self.container!.presentContainer() }Manage dismissing the controller on iPhone in
viewWillDisappear(_:)self.presentedViewController?.dismiss(animated: false, completion: nil)Present the
detailPanelby managing selecting and deselecting map annotations inmapView(_:didSelect:)andmapView(_:didDeselect:)
See moreopen func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) { let selectedAnnotation = view.annotation if selectedAnnotation is MKUserLocation { return } self.devUpdateDetailVC(annotation: selectedAnnotation!) DispatchQueue.main.async { container.pushChildViewController() } for annotation in mapView.annotations { if let annotation = annotation as? MKAnnotation, !annotation.isEqual(selectedAnnotation) { self.container.content.tableView.dataSource = newDataSource self.container.fitToContent() DispatchQueue.main.async { self.container.pushChildViewController() } return } } } open func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) { let selectedAnnotation = view.annotation if selectedAnnotation is MKUserLocation { return } DispatchQueue.main.async { if self.mapView.selectedAnnotations.isEmpty { self.container.popChildViewController() } else { self.container.content.tableView.dataSource = newDataSource self.container.fitToContent() self.container.content.tableView.reloadData() } } }Declaration
Swift
@MainActor open class FUIMapDetailPanel : UIView -
A
FUIMapDetailTagObjectTableViewCellthat inherits fromFUIMapDetailBaseObjectTableViewCellandFUITags. Add tags to the tableViewCell in the upper left corner above the subheadline text.Available:
tags: An array ofStringthat will be wrapped in a bordered cell. These tags will go in the upper left corner of the cell.
Initialization and Configuration
In the
viewDidLoadtableView.register(FUIMapDetailTagObjectTableViewCell.self, forCellReuseIdentifier: FUIMapDetailTagObjectTableViewCell.reuseIdentifier)In the
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
See morelet cell = tableView.dequeueReusableCell(withIdentifier: FUIMapDetailTagObjectTableViewCell.reuseIdentifier, for: indexPath) as! FUIMapDetailTagObjectTableViewCell cell.headlineText = "VA Palo Alto Health Care Sys wraps to two lines..." cell.headlineLabel.numberOfLines = 1 cell.footnoteText = "Medical Center" cell.statusLabel.font = UIFont.preferredFioriFont(forTextStyle: .headline)Declaration
Swift
@MainActor open class FUIMapDetailTagObjectTableViewCell : FUIBaseDrawingTableViewCell<FUIMapDetailTagObjectView> -
Status view component of
FUIMapDetailStatusTableViewCellTypically not used directly by developer.
A view with left aligned text and an optional image. Images are left aligned and placed to the left of the text. Images are expected to be 16px by 16px.
Usage
let statusView = FUIMapDetailStatusView() statusView.statusImage = FUIIconLibrary.indicator.veryHighPriority statusView.status.text = "High"Theming
nuiClass:fdlFUIMapDetailStatusView {}Supported
TEXTclass paths:fdlFUIMapDetailStatusView_status {}Supported
TEXTproperties:font-color: Color; font-style: UIFontTextStyle;Supported
IMAGEclass paths:fdlFUIMapDetailStatusView_statusImage {}Supported
IMAGEproperties:
See moretint-color: Color;Declaration
Swift
@MainActor open class FUIMapDetailStatusView : FUIDrawingView, FUIStatusImageComponent -
An object that manages editing data in the
detailPanel. The developer specifies the items a user can create and which geometries he/she can use. A controller is presented when saving a geometry to add additional changes to the work order. When the geometry is saved, it is up to the developer to update their model with editing geometry.Variables Available in
FUIEditingPanel:createGeometryItems: An array ofFUIMapLegendItemthat displays the types of work orders that can be created. The items are presented in a table and when selected presents the editing panel. The panel takes the title of the item and sets it as the headline. The icon and title text has awhitebackground and a tint color ofUIColor.preferredFioriColor(forStyle: .tintColorDark)basemapTypes: An array ofMKMapTypea user can pick from during editing.MapTypeis returned to the original state after editing is completed. By default, the user can pick from.standard,.hybrid,.mutedStandard, and.satellite.isCreatePointEnabled: ABoolthat enables the creation of a point geometry. By default, point geometry creation is enabled. Select the point symbol on the segmented control within the editing panel to begin editing.isCreatePolylineEnabled: ABoolthat enables the creation of a polyline geometry. By default, polyline geometry creation is enabled. Select the polyline symbol on the segmented control within the editing panel to begin editing.isCreatePolygonEnabled: ABoolthat enables the creation of a polygon geometry. By default, polygon geometry creation is enabled. Select the polygon symbol on the segmented control within the editing panel to begin editing.createGeometryResultsController: A view controller that is presented when an editing geometry is saved. Used to make additional changes to the work order before a save is committed. The controller is presented modally over the map. The saved geometry is handled by the developer in thedidSaveGeometrymethod where the map model should be updated.willShowCreateGeometryResultsController: A closure that provides custom behaviors before showingcreateGeometryResultsController. This closure will only be called ifcreateGeometryResultsControlleris displayed in.pushmode. It is up to the developer to implement this closure and define custom actions before entering the editing results screen.didDismissGeometryResultsController: A closure that provides custom behaviors before dismissingcreateGeometryResultsController. This closure will only be called ifcreateGeometryResultsControlleris displayed in.pushmode. It is up to the developer to implement this closure and define custom actions before dismissing the editing results screen.didCommitGeometryResults: A closure that provides the committed saved geometry. It is up to the developer to implement this closure and update his/her own model with the saved geometry.
Declaration
Swift
open class FUIEditingPanel<GeometryType> where GeometryType : FUIGeometry -
A protocol extending MKAnnotation for storing index and state info that will be used by
See moreFUIMapFloorplanViewController. The properties of this protocol are managed byFUIMapFloorplanViewController. Developer is not supposed to set these properties.Declaration
Swift
public protocol FUIAnnotation : MKAnnotation -
The
FUIMapMarkerAnnotationViewinherits from theMKMarkerAnnotationViewand is presented as an annotation on theMKMapView. It is used to distinguish between location types and set a select priority to individual markers.Note
We disabled setter of
zPositionin order to prevent it from being modified when settingdisplayPriority. SetstickyZPositioninstead.## Available:
priorityIcon: a 17x17 icon image in the upper right corner of the marker. This can appear in both the selected and unselected state.
## Example Initialization and Configuration
@available(iOS 11.0, *) class MyMarker: FUIMarkerAnnotationView { override var annotation: MKAnnotation? { willSet { markerTintColor = UIColor.preferredFioriColor(forStyle: .map1) glyphImage = FUIIconLibrary.map.marker.venue.withRenderingMode(.alwaysTemplate) displayPriority = .defaultLow priorityIcon = FUIIconLibrary.map.marker.veryHighPriority } } }Register within the viewDidLoad()
if #available(iOS 11.0, *) { mapView.register(MyMarker.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier) } else { // Fallback on earlier versions } let point1 = MKPointAnnotation() point1.coordinate = CLLocationCoordinate2D(latitude: 37.3318, longitude: -122.0312) let point2 = MKPointAnnotation() point2.coordinate = CLLocationCoordinate2D(latitude: 37.3988313, longitude: -122.1487375) let annotations = [point1 as MKAnnotation, point2 as MKAnnotation] mapView.addAnnotations(annotations)Set the annotation view in the
mapView(_:viewFor:)method.var view: MKAnnotationView! if let pointAnnotation = annotation as? MKPointAnnotation { if #available(iOS 11.0, *) { view = FUIMarkerAnnotationView(annotation: pointAnnotation, reuseIdentifier: "cell") let annotationImage = FUIIconLibrary.map.marker.venue (view as! FUIMarkerAnnotationView).glyphImage = annotationImage.withRenderingMode(.alwaysTemplate) (view as! FUIMarkerAnnotationView).priorityIcon = FUIIconLibrary.map.marker.veryHighPriority } else { // Fallback on earlier versions view = MKPinAnnotationView(annotation: pointAnnotation, reuseIdentifier: "cell") } } return view## Note:
- Set the
glyphImageto a 20x20 icon.
Declaration
Swift
@available(iOS 11.0, *) @MainActor open class FUIMarkerAnnotationView : MKMarkerAnnotationView -
The
FUIProfileMarkerAnnotationViewinherits from theMKMarkerAnnotationViewand is presented as an annotation on theMKMapView. It is used to distinguish between static points on a map and person location. The annotation can either display a profilePicture or a set of initials to represent the person being annotated.Example Initialization and Configuration
@available(iOS 11.0, *) class MyProfileMarker: FUIProfileMarkerAnnotationView { override var annotation: MKAnnotation? { willSet { markerTintColor = UIColor.preferredFioriColor(forStyle: .map1) glyphImage = FUIIconLibrary.map.marker.venue.withRenderingMode(.alwaysTemplate) } } }Register within the viewDidLoad()
if #available(iOS 11.0, *) { mapView.register(MyProfileMarker.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier) } else { // Fallback on earlier versions } let point1 = MKPointAnnotation() point1.coordinate = CLLocationCoordinate2D(latitude: 37.3318, longitude: -122.0312) let point2 = MKPointAnnotation() point2.coordinate = CLLocationCoordinate2D(latitude: 37.3988313, longitude: -122.1487375) let annotations = [point1 as MKAnnotation, point2 as MKAnnotation] mapView.addAnnotations(annotations) mapView.showAnnotations(annotations, animated: true)Set the annotation view in the
mapView(_:viewFor:)method.var view: MKAnnotationView! if let pointAnnotation = annotation as? MKPointAnnotation { if #available(iOS 11.0, *) { if pointAnnotation.coordinate.latitude == 37.3318 { view = FUIProfileMarkerAnnotationView(annotation: pointAnnotation, reuseIdentifier: "cell") (view as! FUIProfileMarkerAnnotationView).glyphText = "ME" return view } else { view = FUIProfileMarkerAnnotationView(annotation: pointAnnotation, reuseIdentifier: "cell") (view as! FUIProfileMarkerAnnotationView).glyphImage = #imageLiteral(resourceName: "ProfilePic").withRenderingMode(.alwaysOriginal) (view as! FUIProfileMarkerAnnotationView).selectedGlyphImage = #imageLiteral(resourceName: "ProfilePic").withRenderingMode(.alwaysOriginal) return view } } else { // Fallback on earlier versions return nil } } return viewNote:
- Set the
profileImageto a 24x24 icon.
Declaration
Swift
@available(iOS 11.0, *) @MainActor open class FUIProfileMarkerAnnotationView : MKMarkerAnnotationView - Set the
-
The
FUICircleAnnotationViewinherits from theMKAnnotationViewand is presented as a circle annotation on theMKMapView. It is used to display annotation objects which have similar display effect asMKCircleobject.Note
We disabled setter of
zPositionto prevent it from being modified when settingdisplayPriority. SetstickyZPositioninstead.Example
- Add annotation objects to map
let point1 = MKPointAnnotation() point1.coordinate = CLLocationCoordinate2D(latitude: 37.3318, longitude: -122.0312) let point2 = MKPointAnnotation() point2.coordinate = CLLocationCoordinate2D(latitude: 37.3988313, longitude: -122.1487375) let annotations = [point1 as MKAnnotation, point2 as MKAnnotation] mapView.addAnnotations(annotations) - Set the circle annotation view in the
mapView(_:viewFor:)method.
See morelet reuseIdentifier = "DefaultCircleAnnotationView" let view = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier) as? FUICircleAnnotationView ?? FUICircleAnnotationView(annotation: editAnnotation, reuseIdentifier: reuseIdentifier, clusteringIdentifier: nil) view.outerColor = UIColor.preferredFioriColor(forStyle: .primary1) view.outerWidth = 2.0 view.innerColor = UIColor.preferredFioriColor(forStyle: .tintColorTapState) view.circleRadius = 6.0 return viewDeclaration
Swift
@MainActor open class FUICircleAnnotationView : MKAnnotationView - Add annotation objects to map
-
A protocol extending FUIAnnotation and MKOverlay for storing extra info that will be used by
See moreFUIMapFloorplanViewController. The properties of this protocol are managed byFUIMapFloorplanViewController. Developer is not supposed to set these properties.Declaration
Swift
public protocol FUIOverlay : MKOverlay, FUIAnnotation -
Geometry protocol for FUIMapView.
Declaration
Swift
public protocol FUIGeometry : Hashable -
A protocol adopted by an object that plays as the data model of
See moreFUIMKMapFloorplanViewController.Declaration
Swift
public protocol FUIMKMapViewDataSource : AnyObject -
A protocol adopted by an object which plays as the delegate of
See moreFUIMKMapFloorplanViewController.Declaration
Swift
public protocol FUIMKMapViewDelegate : AnyObject -
Component protocol for Map Floorplan properties
See moreDeclaration
Swift
public protocol FUIMapFloorplanComponent -
Component protocol for FUIMapView.
Declaration
Swift
public protocol FUIMapView -
Map point geometry protocol conforms to FUIGeometry.
Declaration
Swift
public protocol FUIPoint : FUIGeometry -
Map polygon geometry protocol conforms to FUIGeometry.
Declaration
Swift
public protocol FUIPolygon : FUIGeometry -
Map polyline geometry protocol conforms to FUIGeometry.
Declaration
Swift
public protocol FUIPolyline : FUIGeometry -
Geometry layer object adds Hashable functionality and other properties.
See moreDeclaration
Swift
public struct FUIGeometryLayer : Hashable -
Generic map Floorplan class for both MapKit and EsriMap.
See moreDeclaration
Swift
public struct FUIMapFloorplan