Learn how to apply renderers and label definitions to a feature layer based on attribute values.
Applications can display feature layer data with different styles to enhance the visualization. The type of Renderer
you choose depends on your application. A SimpleRenderer
applies the same symbol to all features, a UniqueValueRenderer
applies a different symbol to each unique attribute value, and a ClassBreaksRenderer
applies a symbol to a range of numeric values. Renderers are responsible for accessing the data and applying the appropriate symbol to each feature when the layer draws. You can also use a LabelDefinition
to show attribute information for features. Visit the Styles and data visualization documentation to learn more about styling layers.
You can also author, style and save web maps, web scenes, and layers as portal items and then add them to the map in your application. Visit the following tutorials to learn more about adding portal items.
In this tutorial, you will apply different renderers to enhance the visualization of three feature layers with data for the Santa Monica Mountains: Trailheads with a single symbol, Trails based on elevation change and bike use, and Parks and Open Spaces based on the type of park.
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
Steps
Open the Xcode project
-
To start the tutorial, complete the Display a map tutorial or download and unzip the solution.
-
Open the
.xcodeproj
file in Xcode. -
If you downloaded the solution, get an access token and set the API key.
An API Key gives your app access to secure resources used in this tutorial.
-
Go to the Create an API key tutorial to obtain a new API key access token using your ArcGIS Location Platform or ArcGIS Online account. Ensure that the following privilege is enabled: Location services > Basemaps > Basemap styles service. Copy the access token as it will be used in the next step.
-
In Xcode, in the Project Navigator, click MainApp.swift.
-
In the Editor, set the
ArcGISEnvironment.apiKey
property on theArcGIS
with your access token.Environment MainApp.swiftUse dark colors for code blocks init() { ArcGISEnvironment.apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>") }
-
Add app configuration constants
Create a configuration file to specify constants that can be used by the app to connect to data and resources.
-
Add a new swift file named AppConfiguration.swift.
- In Xcode's app menu, select File > New > File....
- Select Swift File from the iOS tab's Source sub-menu.
- Name the file AppConfiguration and ensure your app's target is checked.
- Click Create.
-
Create five static
URL
s: four for accessing feature layers, and a fifth for accessing a static image for use in a picture marker symbol. You will use these resources in future steps.AppConfiguration.swiftUse dark colors for code blocks extension URL { static let bikesTrails = URL(string: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0")! static let parksAndOpenSpaces = URL(string: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space/FeatureServer/0")! static let trails = URL(string: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0")! static let trailheads = URL(string: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads/FeatureServer/0")! static let trailheadImage = URL(string: "https://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png")! }
Create helper method to make a feature layer
Add a helper method that creates a feature layer from a given URL
.
-
Open
Content
in the Project Navigator. Add a new method namedView.swift make
.Feature Layer(url : UR L) ContentView.swiftUse dark colors for code blocks private func makeFeatureLayer(url: URL) -> FeatureLayer { let serviceFeatureTable = ServiceFeatureTable(url: url) let featureLayer = FeatureLayer(featureTable: serviceFeatureTable) return featureLayer }
Add a layer with a unique value renderer
Create a method to apply a different symbol for each type of park area to the Parks and Open Spaces feature layer.
-
Add a new method named
make
inOpen Space Layer() Content
.View.swift UniqueValue
assigns a symbol to a value or values. A unique value renderer uses a collection of unique values to assign the appropriate symbol for each feature it renderers.For this example, the renderer uses a feature's
TYPE
attribute value to apply the correct symbol.ContentView.swiftUse dark colors for code blocks private func makeOpenSpaceLayer() { // Creates a parks and open spaces feature layer. let featureLayer = makeFeatureLayer(url: .parksAndOpenSpaces) // Creates fill symbols. let purpleFillSymbol = SimpleFillSymbol(style: .solid, color: .purple, outline: .none) let greenFillSymbol = SimpleFillSymbol(style: .solid, color: .green, outline: .none) let blueFillSymbol = SimpleFillSymbol(style: .solid, color: .blue, outline: .none) let redFillSymbol = SimpleFillSymbol(style: .solid, color: .red, outline: .none) // Creates a unique value for natural areas, regional open spaces, local parks & regional recreation parks. let naturalAreas = UniqueValue(description: "Natural Areas", label: "Natural Areas", symbol: purpleFillSymbol, values: ["Natural Areas"]) let regionalOpenSpace = UniqueValue(description: "Regional Open Space", label: "Regional Open Space", symbol: greenFillSymbol, values: ["Regional Open Space"]) let localPark = UniqueValue(description: "Local Park", label: "Local Park", symbol: blueFillSymbol, values: ["Local Park"]) let regionalRecreationPark = UniqueValue(description: "Regional Recreation Park", label: "Regional Recreation Park", symbol: redFillSymbol, values: ["Regional Recreation Park"]) // Creates and assigns a unique value renderer to the feature layer. let openSpacesUniqueValueRenderer = UniqueValueRenderer(fieldNames: ["TYPE"], uniqueValues: [naturalAreas, regionalOpenSpace, localPark, regionalRecreationPark], defaultLabel: "Open Spaces", defaultSymbol: .none) featureLayer.renderer = openSpacesUniqueValueRenderer // Sets the layer opacity to semi-transparent. featureLayer.opacity = 0.2 // Adds the feature layer to the map. map.addOperationalLayer(featureLayer) }
-
Update the
Map
task to call the newView make
method.Open Space Layer() ContentView.swiftUse dark colors for code blocks // Displays the map. MapView(map: map) .task { makeOpenSpaceLayer() }
-
Press Command + R to run the app.
When the app opens, Parks and Open Spaces feature layer is added to the map. The map displays the different types of parks and open spaces with four unique symbols.
Add a layer with a class breaks renderer
Create a method to apply a different symbol for each of the five ranges of elevation gain to the Trails feature layer.
-
Add a new method named
add
.Trails Layer() A
ClassBreak
assigns a symbol to a range of values.For this example, the renderer uses each feature's
ELEV
attribute value to classify it into a defined range (class break) and apply the corresponding symbol._GAIN ContentView.swiftUse dark colors for code blocks private func addTrailsLayer() { // Creates a trails feature layer. let featureLayer = makeFeatureLayer(url: .trails) // Creates simple line symbols. let firstClassSymbol = SimpleLineSymbol(style: .solid, color: .purple, width: 3.0) let secondClassSymbol = SimpleLineSymbol(style: .solid, color: .purple, width: 4.0) let thirdClassSymbol = SimpleLineSymbol(style: .solid, color: .purple, width: 5.0) let fourthClassSymbol = SimpleLineSymbol(style: .solid, color: .purple, width: 6.0) let fifthClassSymbol = SimpleLineSymbol(style: .solid, color: .purple, width: 7.0) // Creates 5 class breaks. let firstClassBreak = ClassBreak(description: "Under 500", label: "0 - 500", minValue: 0.0, maxValue: 500.0, symbol: firstClassSymbol) let secondClassBreak = ClassBreak(description: "501 to 1000", label: "501 - 1000", minValue: 501.0, maxValue: 1000.0, symbol: secondClassSymbol) let thirdClassBreak = ClassBreak(description: "1001 to 1500", label: "1001 - 1500", minValue: 1001.0, maxValue: 1500.0, symbol: thirdClassSymbol) let fourthClassBreak = ClassBreak(description: "1501 to 2000", label: "1501 - 2000", minValue: 1501.0, maxValue: 2000.0, symbol: fourthClassSymbol) let fifthClassBreak = ClassBreak(description: "2001 to 2300", label: "2001 - 2300", minValue: 2001.0, maxValue: 2300.0, symbol: fifthClassSymbol) let elevationBreaks = [firstClassBreak, secondClassBreak, thirdClassBreak, fourthClassBreak, fifthClassBreak] // Creates and assigns a class breaks renderer to the feature layer. let elevationClassBreaksRenderer = ClassBreaksRenderer(fieldName: "ELEV_GAIN", classBreaks: elevationBreaks) featureLayer.renderer = elevationClassBreaksRenderer // Sets the layer opacity to semi-transparent. featureLayer.opacity = 0.75 // Adds the feature layer to the map. map.addOperationalLayer(featureLayer) }
-
Update the
Map
task to call the newView add
method.Trails Layer() ContentView.swiftUse dark colors for code blocks // Displays the map. MapView(map: map) .task { makeOpenSpaceLayer() addTrailsLayer() }
-
Press Command + R to run the app.
When the app opens, the Trails feature layer is added to the map. The map displays trails with different symbols depending on trail elevation.
Add layers with definition expressions
You can use a definition expression to define a subset of features to display. Features that do not meet the expression criteria are not displayed by the layer. In the following steps, you will create two methods that use a definition expression to apply a symbol to a subset of features in the Trails feature layer.
FeatureLayer.definitionExpression
uses a SQL expression to limit the features available for query and display. Your code will create two layers that each display a different subset of trails based on the value for the USE
field. Trails that allow bikes will be symbolized with a blue symbol ("
) and those that don't will be red ("
). Another way to symbolize these features would be to create a UniqueValueRenderer
that applies a different symbol for these values.
-
Add a method with a definition expression to filter for trails that permit bikes.
ContentView.swiftUse dark colors for code blocks private func addBikeOnlyTrailsLayer() { // Creates a trails feature layer. let featureLayer = makeFeatureLayer(url: .bikesTrails) // Writes a definition expression to filter for trails that do permit the use of bikes. featureLayer.definitionExpression = "USE_BIKE = 'Yes'" // Creates and assigns a simple renderer to the feature layer. let bikeTrailSymbol = SimpleLineSymbol(style: .dot, color: .blue, width: 2.0) let bikeTrailRenderer = SimpleRenderer(symbol: bikeTrailSymbol) featureLayer.renderer = bikeTrailRenderer // Adds the feature layer to the map. map.addOperationalLayer(featureLayer) }
-
Add another method with a definition expression to filter for trails that don't allow bikes.
ContentView.swiftUse dark colors for code blocks private func addNoBikeTrailsLayer() { // Creates a no bike trails feature layer. let featureLayer = makeFeatureLayer(url: .bikesTrails) // Writes a definition expression to filter for trails that don't permit the use of bikes. featureLayer.definitionExpression = "USE_BIKE = 'No'" // Creates and assigns a simple renderer to the feature layer. let noBikeTrailSymbol = SimpleLineSymbol(style: .dot, color: .red, width: 2.0) let noBikeTrailRenderer = SimpleRenderer(symbol: noBikeTrailSymbol) featureLayer.renderer = noBikeTrailRenderer // Adds the feature layer to the map. map.addOperationalLayer(featureLayer) }
-
Update the
Map
task to call the newView add
andBike Only Trails Layer() add
methods.No Bike Trails Layer() ContentView.swiftUse dark colors for code blocks // Displays the map. MapView(map: map) .task { makeOpenSpaceLayer() addTrailsLayer() addNoBikeTrailsLayer() addBikeOnlyTrailsLayer() }
-
Press Command + R to run the app.
When the app opens, two Trails feature layers are added to the map. One shows where bikes are permitted and the other where they are prohibited.
Add a layer with a label definition
Create a method to style trailheads with hiker images and labels for the Trailheads feature layer.
-
Create a helper method named
make
to define a label definition based on a specific attribute of the feature layerLabel Definition() TRL
. Also define label placement and symbol._NAME ContentView.swiftUse dark colors for code blocks private func makeLabelDefinition() -> LabelDefinition { let trailHeadsTextSymbol = TextSymbol() trailHeadsTextSymbol.color = .white trailHeadsTextSymbol.size = 20.0 trailHeadsTextSymbol.haloColor = .red trailHeadsTextSymbol.haloWidth = 2.0 trailHeadsTextSymbol.fontFamily = "Noto Sans" trailHeadsTextSymbol.fontStyle = .italic trailHeadsTextSymbol.fontWeight = .normal // Makes an arcade label expression. let expression = "$feature.TRL_NAME" let arcadeLabelExpression = ArcadeLabelExpression(arcadeString: expression) let labelDefinition = LabelDefinition(labelExpression: arcadeLabelExpression, textSymbol: trailHeadsTextSymbol) labelDefinition.placement = .pointAboveCenter return labelDefinition }
-
Add a method named
add
.Trailheads Layer() Use a
PictureMarkerSymbol
to draw a trailhead hiker image. Use theLabelDefinition
to label each trailhead by its name.ContentView.swiftUse dark colors for code blocks private func addTrailheadsLayer() { // Creates a trailheads feature layer. let featureLayer = makeFeatureLayer(url: .trailheads) let pictureMarkerSymbol = PictureMarkerSymbol(url: .trailheadImage) pictureMarkerSymbol.height = 18.0 pictureMarkerSymbol.width = 18.0 let simpleRenderer = SimpleRenderer(symbol: pictureMarkerSymbol) featureLayer.renderer = simpleRenderer featureLayer.labelsAreEnabled = true let trailHeadsDefinition = makeLabelDefinition() featureLayer.addLabelDefinition(trailHeadsDefinition) // Adds the feature layer to the map. map.addOperationalLayer(featureLayer) }
-
Update the
Map
task to call the newView add
method.Trailheads Layer() ContentView.swiftUse dark colors for code blocks // Displays the map. MapView(map: map) .task { makeOpenSpaceLayer() addTrailsLayer() addNoBikeTrailsLayer() addBikeOnlyTrailsLayer() addTrailheadsLayer() }
-
Press Command + R to run the app.
If you are using the Xcode simulator your system must meet these minimum requirements: macOS 14 (Sonoma), Xcode 16, iOS 18. If you are using a physical device, then refer to the system requirements.
When the app opens, all the layers you've created and symbolized are displayed on the map.
- Parks and open spaces are displayed with four unique symbols
- Trails use different symbols (line widths) depending on trail elevation
- Trails are blue where bikes are permitted and red where they are prohibited
- Trailheads are displayed with a hiker icon and labels display each trail's name
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: