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
FUIGeometryLayer
s 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
MKMapView
instance 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 MKAnnotationView
s, MKPolyline
s, and MKPolygon
s 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 FUIMapLegendItem
s. 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.
SearchResults
tableView
dataSource
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.
SearchResults
tableView
delegate
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)
SearchResults
searchbar
delegate
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)
SearchResults
Data 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
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 showsmapAnnotations
and their title.settingsController
: A controller presented as aformSheet
over 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
: ABool
that 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
: ABool
that enables editing of point geometries.isCreatePolylineEnabled
: ABool
that enables editing of polyline geometries.isCreatePolygonEnabled
: ABool
that 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 morecreateGeometryResultsController
where 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
open class FUIMapFloorplanViewController<InnerView, EditingGeometryWrapper, EditingTypes> : FUIBaseDrawingViewController<InnerView>, FUIMapFloorplanComponent where InnerView : FUIMapFloorplanContentView, EditingGeometryWrapper : FUIManageRepresentation, EditingTypes : FUIGeometryTypeWrapper
-
A subclass of
MKMapView
is designed to be used with MapKit framework. You can useFUIMKMapView
to display map information and to manipulate the map contents from your application. TheFUIMKMapView
class supports the ability to cache common map interface objects: annotations and overlays. NativeMKMapView
API 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
open class FUIMKMapView : MKMapView
-
The main view of
See moreFUIMKMapFloorplanViewController
Declaration
Swift
open class FUIMKMapFloorplanContentView : FUIMapFloorplanContentView
-
A subclass of
FUIMapFloorplanViewController
designed 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
FUIGeometryLayer
s. By assigning geometries onto different layers, you can show/hide all geometries on a specified layer using setLayerHidden(_:hidden:) api.- Implement
FUIMKMapViewDataSource
methods.
In the floorplan controller viewDidLoad() set the datasource.
self.dataSource = dataSource
func 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
FUIMKMapViewDelegate
object is not able to manage these objects.- Implement
MKMapViewDelegate
methods as needed.
Developer can supply custom annotation views. FUIMarkerAnnotationView is provided by the floorplan.
mapView.delegate = delegate
open 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 }
FUIMKMapViewDelegate
provides more functionalities that you can make your app more powerful.
In the floorplan controller viewDidLoad() set the delegate.
self.delegate = delegate
Determine 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
open class FUIMKMapFloorplanViewController : FUIMapFloorplanViewController<FUIMKMapFloorplanContentView, MKEditingGeometryWrapper, MKEditingTypes>, EditingGeometryProducing
- Implement
-
A View that wraps the
FUIMapToolbarButton
in a vertical stack.- The
FUIMapToolbar
holds a maximum of 6FUIMapToolbarButton
. - Default variants of
FUIMapToolbarButton
exist within the SDK. See,FUIMapToolbarSettingsButton
,FUIMapToolbarUserLocationButton
,FUIMapToolbarZoomExtentButton
, orFUIMapToolbarLegendButton
- The
FUIMapToolbar
can be presented in either a dark or light variant. - The
FUIMapToolbar
will be pinned to the givenMKMapView
in 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
open class FUIMapToolbar : UIView, FUIBackgroundSchemeSupporting
- The
-
FUIMapToolbarButton
inherits 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
FUIMapToolbarButton
for custom variants
See
See provided default variants:FUIMapToolbarSettingsButton
,FUIMapToolbarUserLocationButton
,FUIMapToolbarZoomExtentButton
, andFUIMapToolbarLegendButton
See
SeeFUIMapToolbarSettingsButton
documentation for supplementaryDevMapSettingsViewController
classDeclaration
Swift
open class FUIMapToolbarButton : FUIButton
-
A
UIViewController
containing a tableView ofFUIMapLegendItem
s. 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 ofFUIMapLegendItem
that will be displayed in the tableView.
Declaration
Swift
open class FUIResizablePopoverContainer : UIViewController
-
FUIMapLegend
extendsUIViewController
to show the Map Legend.FUIMapLegend
is presented in aUIPopoverView
on iPad and presented in aUIPresentationController
on iPhoneAvailable in
FUIMapLegend
:headerTextView
: aTextView
intended to display a footnote text.passThroughViews
: an array ofUIView
that a user can interact with while popover is visible
Example Initialization and Configuration:
In view controller’s
viewDidLoad
method: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
See implementation ofFUIMapLegend
using aFUIMapToolbarLegendButton
for a complete implementation.Declaration
Swift
open class FUIMapLegend : FUIResizablePopoverContainer
extension FUIMapLegend: UIViewControllerTransitioningDelegate
extension FUIMapLegend: UITableViewDelegate
extension FUIMapLegend: UITableViewDataSource
-
FUIMapLegendItem
is a struct to represent an entry in the Map Legend. AFUIMapLegendItem
can 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
: aString
that describes theFUIMapLegendItem
type
: aFUIMapLegendItemType
designated for the item.backgroundColor
: aUIColor
displayed as a backgroundColor for the itemtintColor
: aUIColor
displayed as a tintColor for the itemicon
: aFUIMapLegendIcon
for the designated item.line
: aFUIMapLegendLine
for the designated item.fillItem
: aFUIMapLegendFillItem
for 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
-
FUIMapLegendIcon
is 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
-
FUIMapLegendFillItem
is aUIView
that presents a square view with a fill color and border color.Available in FUIMapLegendFillItem:
fillColor
: aUIColor
that is the fill color of the square viewborderColor
: aUIColor
that 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
public class FUIMapLegendFillItem : UIView
-
FUIMapLegendLine
is 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 ofNSNumber
objects specifying the lenghts of line segmentsdashPhase
: aCGFloat
describing 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
FUIMapDetailPanel
as 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
: AString
used as the header text inside the panel. The headline text can wrap up to two lines and truncates at the tail.subheadlineText
: AString
used as the subheadline text inside the panel. The subheadline text gradually disappears while thetableView
scrolls.didSelectTitleHandler
: An optional handler that can be set by the developer that is executed when theheadlineText
is tapped. If thedidSelectTitleHandler
is not nil, theheadlineText
text 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.automaticDimension
Declaration
Swift
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 = dataSource
Declaration
Swift
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 = delegate
Declaration
Swift
public class FUIMapDetailPanelSearchBar : FUISearchBar
-
A View Controller component within the
FUIMapDetailPanel
as 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
: AUITableView
that displays search results. Developer must set the tableView datasource and delegate.searchBar
: AFUIMapDetailPanelSearchBar
that should filter data. Developer must set the searchBar delegate.preferredContentSize
: ACGSize
that determines the size of theUIViewController
. This variable drives the resizing capabilities of the view and must set correctly and properly updated.isApplyingBlurBackground
: ABool
that determines if thetableView
will use its blurredBackground. Setting it to false will set the tableView to theUITableView
default values.isApplyingBlurBackground
default value is true.searchBar
: AFUIMapDetailPanelSearchBar
used 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 = searchBarDelegate
Declaration
Swift
public class FUIMapDetailPanelSearchResultsViewController : FUIMapDetailPanelViewController
-
A View Component that wraps the
FUIMapDetailPanelSearchResultsViewController
as thesearchResultsController
and theFUIMapDetailPanelContentViewController
as thecontent
. Switching between the two view controllers should be driven by thepushChildViewController
andpopChildViewController
methods in the developer’smapView(_:didSelect:)
andmapView(_:didDeselect:)
methods.## iPhone The
searchResults
andcontent
will 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 givenpinMapView
and will resize accordingly. ThefitToContent
method 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
: ABool
that determines if the child views will have a blurred background.isSearchEnabled
: A Boolean value to instantiate search.searchResults
: AFUIMapDetailPanelSearchResultsViewController
used for the search function. Manipulate itstableView
to show search results. The developer must set thedatasource
and delegate methods.content
: AFUIMapDetailPanelContentViewController
used for showing the details. The developer must set thedatasource
and 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.automaticDimension
Manage 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
detailPanel
by 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
open class FUIMapDetailPanel : UIView
-
A
FUIMapDetailTagObjectTableViewCell
that inherits fromFUIMapDetailBaseObjectTableViewCell
andFUITags
. Add tags to the tableViewCell in the upper left corner above the subheadline text.Available:
tags
: An array ofString
that will be wrapped in a bordered cell. These tags will go in the upper left corner of the cell.
Initialization and Configuration
In the
viewDidLoad
tableView.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
open class FUIMapDetailTagObjectTableViewCell : FUIBaseDrawingTableViewCell<FUIMapDetailTagObjectView>
-
Status view component of
FUIMapDetailStatusTableViewCell
Typically 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
TEXT
class paths:fdlFUIMapDetailStatusView_status {}
Supported
TEXT
properties:font-color: Color; font-style: UIFontTextStyle;
Supported
IMAGE
class paths:fdlFUIMapDetailStatusView_statusImage {}
Supported
IMAGE
properties:
See moretint-color: Color;
Declaration
Swift
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 ofFUIMapLegendItem
that 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 awhite
background and a tint color ofUIColor.preferredFioriColor(forStyle: .tintColorDark)
basemapTypes
: An array ofMKMapType
a user can pick from during editing.MapType
is returned to the original state after editing is completed. By default, the user can pick from.standard
,.hybrid
,.mutedStandard
, and.satellite
.isCreatePointEnabled
: ABool
that 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
: ABool
that 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
: ABool
that 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 thedidSaveGeometry
method where the map model should be updated.willShowCreateGeometryResultsController
: A closure that provides custom behaviors before showingcreateGeometryResultsController
. This closure will only be called ifcreateGeometryResultsController
is displayed in.push
mode. 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 ifcreateGeometryResultsController
is displayed in.push
mode. 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
FUIMapMarkerAnnotationView
inherits from theMKMarkerAnnotationView
and 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
zPosition
in order to prevent it from being modified when settingdisplayPriority
. SetstickyZPosition
instead.## 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
glyphImage
to a 20x20 icon.
Declaration
Swift
@available(iOS 11.0, *) open class FUIMarkerAnnotationView : MKMarkerAnnotationView
-
The
FUIProfileMarkerAnnotationView
inherits from theMKMarkerAnnotationView
and 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 view
Note:
- Set the
profileImage
to a 24x24 icon.
Declaration
Swift
@available(iOS 11.0, *) open class FUIProfileMarkerAnnotationView : MKMarkerAnnotationView
- Set the
-
The
FUICircleAnnotationView
inherits from theMKAnnotationView
and is presented as a circle annotation on theMKMapView
. It is used to display annotation objects which have similar display effect asMKCircle
object.Note
We disabled setter of
zPosition
to prevent it from being modified when settingdisplayPriority
. SetstickyZPosition
instead.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 view
Declaration
Swift
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