Learn how to apply renderers

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
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
Develop or Download
You have two options for completing this tutorial:
Option 1: Develop the code
To start the tutorial, complete the Display a map tutorial. This creates a map to display the Santa Monica Mountains in California using the topographic basemap from the ArcGIS Basemap Styles service
Open an Xcode project
- Open the
.xcodeprojproject you created by completing the Display a map tutorial. - Continue with the following instructions to apply renderers and label definitions to a feature layer based on attribute values.
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
URLs: 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.swiftextension 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
ContentView.swiftin the Project Navigator. Add a new method namedmakeFeatureLayer(url: URL).ContentView.swiftprivate 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
makeOpenSpaceLayer()inContentView.swift.UniqueValueassigns 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
TYPEattribute value to apply the correct symbol.ContentView.swiftprivate 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
MapViewtask to call the newmakeOpenSpaceLayer()method.ContentView.swift// 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
addTrailsLayer().A
ClassBreakassigns a symbol to a range of values.For this example, the renderer uses each feature’s
ELEV_GAINattribute value to classify it into a defined range (class break) and apply the corresponding symbol.ContentView.swiftprivate 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
MapViewtask to call the newaddTrailsLayer()method.ContentView.swift// 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_BIKE field. Trails that allow bikes will be symbolized with a blue symbol ("USE_BIKE = 'Yes'") and those that don’t will be red ("USE_BIKE = 'No'"). 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.swiftprivate 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.swiftprivate 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
MapViewtask to call the newaddBikeOnlyTrailsLayer()andaddNoBikeTrailsLayer()methods.ContentView.swift// 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
makeLabelDefinition()to define a label definition based on a specific attribute of the feature layerTRL_NAME. Also define label placement and symbol.ContentView.swiftprivate func makeLabelDefinition() -> LabelDefinition {let trailHeadsTextSymbol = TextSymbol()trailHeadsTextSymbol.color = .whitetrailHeadsTextSymbol.size = 20.0trailHeadsTextSymbol.haloColor = .redtrailHeadsTextSymbol.haloWidth = 2.0trailHeadsTextSymbol.fontFamily = "Noto Sans"trailHeadsTextSymbol.fontStyle = .italictrailHeadsTextSymbol.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 = .pointAboveCenterreturn labelDefinition} -
Add a method named
addTrailheadsLayer().Use a
PictureMarkerSymbolto draw a trailhead hiker image. Use theLabelDefinitionto label each trailhead by its name.ContentView.swiftprivate func addTrailheadsLayer() {// Creates a trailheads feature layer.let featureLayer = makeFeatureLayer(url: .trailheads)let pictureMarkerSymbol = PictureMarkerSymbol(url: .trailheadImage)pictureMarkerSymbol.height = 18.0pictureMarkerSymbol.width = 18.0let simpleRenderer = SimpleRenderer(symbol: pictureMarkerSymbol)featureLayer.renderer = simpleRendererfeatureLayer.labelsAreEnabled = truelet trailHeadsDefinition = makeLabelDefinition()featureLayer.addLabelDefinition(trailHeadsDefinition)// Adds the feature layer to the map.map.addOperationalLayer(featureLayer)} -
Update the
MapViewtask to call the newaddTrailheadsLayer()method.ContentView.swift// Displays the map.MapView(map: map).task {makeOpenSpaceLayer()addTrailsLayer()addNoBikeTrailsLayer()addBikeOnlyTrailsLayer()addTrailheadsLayer()}
Run the solution
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
Alternatively, you can download the tutorial solution, as follows.
Option 2: Download the solution
-
Click the
Download solutionlink under Solution and unzip the file to a location on your machine. -
Open the
.xcodeprojfile in Xcode.
Since the downloaded solution does not contain authentication credentials, you must first set up authentication to create credentials, and then add the developer credentials to the solution.
Set up authentication
To access the secure ArcGIS location services
You can implement API key authentication or user authentication in this tutorial. Compare the differences below:
API key authentication
- Users are not required to sign in.
- Requires creating an API key credential
API key credentials are an item that contains the parameters used to create and manage long-lived access tokens for API key authentication. They are a type of developer credential. with the correct privileges. - API keys
An API key is a long-lived access token created using API key credentials. They are valid for up to one year and are typically embedded directly into client applications. are long-lived access tokens. - Service usage is billed to the API key owner/developer.
- Simplest authentication method to implement.
- Recommended approach for new ArcGIS developers.
Learn more in API key authentication.
User authentication
- Users are required to sign in with an ArcGIS account
An ArcGIS account is an identity with a user type and set of privileges that can access specific ArcGIS products, tools, APIs, services, and resources. The main account types that can be used for development are an ArcGIS Location Platform account, ArcGIS Online account, and ArcGIS Enterprise account. ArcGIS Location Platform and ArcGIS Online accounts are also associated with a subscription. . - User accounts must have privilege
Privileges are a set of permissions assigned to ArcGIS accounts, developer credentials, and applications that grant access to secure resources and functionality in ArcGIS. to access the ArcGIS servicesA service, also known as an ArcGIS service, is software that supports an ArcGIS REST API and provides geospatial functionality or data. A service can be hosted by Esri or in ArcGIS Enterprise. used in application. - Requires creating OAuth credentials
OAuth credentials are an item that contains parameters required to implement user authentication or app authentication, including a .client_id,client_secret, and redirect URIs. They are a type of developer credential. - Application uses a redirect URL and client ID.
- Service usage is billed to the organization of the user signed into the application.
Learn more in User authentication.
To complete this tutorial, click on the tab in the switcher below for your authentication type of choice, either API key authentication or User authentication.
Create a new API key access token
-
Complete the Create an API key tutorial and create an API key with the following privilege(s)
Privileges are a set of permissions assigned to ArcGIS accounts, developer credentials, and applications that grant access to secure resources and functionality in ArcGIS. :- Privileges
- Location services > Basemaps
- Privileges
-
Copy and paste the API key access token into a safe location. It will be used in a later step.
Create new OAuth credentials to access the secure resources used in this tutorial.
-
Complete the Create OAuth credentials for user authentication tutorial to obtain a Client ID and Redirect URL.
A
Client IDuniquely identifies your app on the authenticating server. If the server cannot find an app with the provided Client ID, it will not proceed with authentication.The
Redirect URL(also referred to as a callback url) is used to identify a response from the authenticating server when the system returns control back to your app after an OAuth login. Since it does not necessarily represent a valid endpoint that a user could navigate to, the redirect URL can use a custom scheme, such asmy-app://auth. It is important to make sure the redirect URL used in your app’s code matches a redirect URL configured on the authenticating server. -
Copy and paste the Client ID and Redirect URL into a safe location. They will be used in a later step.
All users that access this application need account privileges
Set developer credentials in the solution
To allow your app users to access ArcGIS location services
Pass your API Key access token to the ArcGISEnvironment.
-
In the Project Navigator, click MainApp.swift.
-
Set the
AuthenticationModeto.apiKey.MainApp.swift// Change the `AuthenticationMode` to `.apiKey` if your application uses API key authentication.private var authenticationMode: AuthenticationMode { .apiKey } -
Set the
apiKeyproperty with your API key access token.MainApp.swift31 collapsed lines// Copyright 2022 Esri//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.import SwiftUIimport ArcGISimport ArcGISToolkit@mainstruct MainApp: App {// The authentication mode.private enum AuthenticationMode {case apiKeycase user}// Change the `AuthenticationMode` to `.apiKey` if your application uses API key authentication.private var authenticationMode: AuthenticationMode { .apiKey }// Please enter an API key access token if your application uses API key authentication.private let apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>")43 collapsed lines// Setup an `Authenticator` with OAuth configuration if your application uses OAuth credentials.@ObservedObject var authenticator = Authenticator(oAuthUserConfigurations: [OAuthUserConfiguration(// Please enter OAuth credentials for user authentication.portalURL: URL(string: "<#YOUR-PORTAL-URL#>")!,clientID: "<#YOUR-CLIENT-ID#>",redirectURL: URL(string: "<#YOUR-REDIRECT-URL#>")!)])func setAuthentication() {switch authenticationMode {case .apiKey:ArcGISEnvironment.apiKey = apiKeycase .user:ArcGISEnvironment.authenticationManager.arcGISAuthenticationChallengeHandler = authenticator}}init() {setAuthentication()}var body: some SwiftUI.Scene {WindowGroup {ContentView().authenticator(authenticator).ignoresSafeArea()}}}
Best Practice: The access token is stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.
Use the Authenticator toolkit component to manage your OAuth credentialsclient_id, client_secret, and redirect URIs. They are a type of developer credential. ArcGISEnvironment.
-
In the Project Navigator, click MainApp.swift.
-
Set the
AuthenticationModeto.user.MainApp.swift// Change the `AuthenticationMode` to `.user` if your application uses OAuth credentials.private var authenticationMode: AuthenticationMode { .user } -
Set your
portalURL,clientIDandredirectURLvalues.MainApp.swift36 collapsed lines// Copyright 2022 Esri//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.import SwiftUIimport ArcGISimport ArcGISToolkit@mainstruct MainApp: App {// The authentication mode.private enum AuthenticationMode {case apiKeycase user}// Change the `AuthenticationMode` to `.user` if your application uses OAuth credentials.private var authenticationMode: AuthenticationMode { .apiKey }// Please enter an API key access token if your application uses API key authentication.private let apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>")// Setup an `Authenticator` with OAuth configuration if your application uses OAuth credentials.@ObservedObject var authenticator = Authenticator(oAuthUserConfigurations: [OAuthUserConfiguration(// Please enter OAuth credentials for user authentication.portalURL: URL(string: "<#YOUR-PORTAL-URL#>")!,clientID: "<#YOUR-CLIENT-ID#>",redirectURL: URL(string: "<#YOUR-REDIRECT-URL#>")!)])28 collapsed linesfunc setAuthentication() {switch authenticationMode {case .apiKey:ArcGISEnvironment.apiKey = apiKeycase .user:ArcGISEnvironment.authenticationManager.arcGISAuthenticationChallengeHandler = authenticator}}init() {setAuthentication()}var body: some SwiftUI.Scene {WindowGroup {ContentView().authenticator(authenticator).ignoresSafeArea()}}}
Best Practice: The OAuth credentials are stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.
Run the solution
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: