Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Samples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@
10BD9EB52BF51F9000ABDBD5 /* GenerateOfflineMapWithCustomParametersView.Model.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = 10BD9EB32BF51B4B00ABDBD5 /* GenerateOfflineMapWithCustomParametersView.Model.swift */; };
10CFF4CA2DBAAFAC0027F144 /* AddFeatureLayerWithTimeOffsetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10CFF4C92DBAAFAC0027F144 /* AddFeatureLayerWithTimeOffsetView.swift */; };
10CFF5082DC1A3850027F144 /* AddFeatureLayerWithTimeOffsetView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = 10CFF4C92DBAAFAC0027F144 /* AddFeatureLayerWithTimeOffsetView.swift */; };
10CFF50B2DC2EC990027F144 /* ApplyClassBreaksRendererToSublayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10CFF50A2DC2EC990027F144 /* ApplyClassBreaksRendererToSublayerView.swift */; };
10CFF54C2DCD4DFA0027F144 /* ApplyClassBreaksRendererToSublayerView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = 10CFF50A2DC2EC990027F144 /* ApplyClassBreaksRendererToSublayerView.swift */; };
10D321932BDB187400B39B1B /* naperville_imagery.tpkx in Resources */ = {isa = PBXBuildFile; fileRef = 10D321922BDB187400B39B1B /* naperville_imagery.tpkx */; settings = {ASSET_TAGS = (GenerateOfflineMapWithLocalBasemap, ); }; };
10D321962BDB1CB500B39B1B /* GenerateOfflineMapWithLocalBasemapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10D321952BDB1CB500B39B1B /* GenerateOfflineMapWithLocalBasemapView.swift */; };
10D321972BDC3B4900B39B1B /* GenerateOfflineMapWithLocalBasemapView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = 10D321952BDB1CB500B39B1B /* GenerateOfflineMapWithLocalBasemapView.swift */; };
Expand Down Expand Up @@ -646,6 +648,7 @@
88E52E6C2DC960EA00F48409 /* ApplyFunctionToRasterFromServiceView.swift in Copy Source Code Files */,
00FA4E5F2DC568DF008A34CF /* AddRastersAndFeatureTablesFromGeopackageView.swift in Copy Source Code Files */,
0072C7FB2DBAC1A0001502CA /* AddIntegratedMeshLayerView.swift in Copy Source Code Files */,
10CFF54C2DCD4DFA0027F144 /* ApplyClassBreaksRendererToSublayerView.swift in Copy Source Code Files */,
1C38915E2DBC3EDC00ADFDDC /* AddWFSLayerView.swift in Copy Source Code Files */,
1C29C95A2DBAE5770074028F /* AddWMTSLayerView.swift in Copy Source Code Files */,
004421912DB96A7800249FEE /* AddFeatureCollectionLayerFromQueryView.swift in Copy Source Code Files */,
Expand Down Expand Up @@ -950,6 +953,7 @@
10B782072BE5A058007EAE6C /* GenerateOfflineMapWithCustomParametersView.CustomParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateOfflineMapWithCustomParametersView.CustomParameters.swift; sourceTree = "<group>"; };
10BD9EB32BF51B4B00ABDBD5 /* GenerateOfflineMapWithCustomParametersView.Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateOfflineMapWithCustomParametersView.Model.swift; sourceTree = "<group>"; };
10CFF4C92DBAAFAC0027F144 /* AddFeatureLayerWithTimeOffsetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeatureLayerWithTimeOffsetView.swift; sourceTree = "<group>"; };
10CFF50A2DC2EC990027F144 /* ApplyClassBreaksRendererToSublayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplyClassBreaksRendererToSublayerView.swift; sourceTree = "<group>"; };
10D321922BDB187400B39B1B /* naperville_imagery.tpkx */ = {isa = PBXFileReference; lastKnownFileType = file; path = naperville_imagery.tpkx; sourceTree = "<group>"; };
10D321952BDB1CB500B39B1B /* GenerateOfflineMapWithLocalBasemapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateOfflineMapWithLocalBasemapView.swift; sourceTree = "<group>"; };
1C0C1C3429D34DAE005C8B24 /* ChangeViewpointView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeViewpointView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1410,6 +1414,7 @@
D7C16D172AC5F6C100689E89 /* Animate 3D graphic */,
D77570BC2A29427200F490CD /* Animate images with image overlay */,
1C38915F2DC02F0800ADFDDC /* Apply blend renderer to hillshade */,
10CFF5092DC2EC3E0027F144 /* Apply class breaks renderer to sublayer */,
4C81273A2DCA9E03006EF7D2 /* Apply colormap renderer to raster */,
D7F2A02C2CD00F1C0008D981 /* Apply dictionary renderer to feature layer */,
D70789912CD160FD000DF215 /* Apply dictionary renderer to graphics overlay */,
Expand Down Expand Up @@ -1830,6 +1835,14 @@
path = "Add feature layer with time offset";
sourceTree = "<group>";
};
10CFF5092DC2EC3E0027F144 /* Apply class breaks renderer to sublayer */ = {
isa = PBXGroup;
children = (
10CFF50A2DC2EC990027F144 /* ApplyClassBreaksRendererToSublayerView.swift */,
);
path = "Apply class breaks renderer to sublayer";
sourceTree = "<group>";
};
10D321912BDB187400B39B1B /* 85282f2aaa2844d8935cdb8722e22a93 */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4035,6 +4048,7 @@
E066DD4028610F55004D3D5B /* AddSceneLayerFromServiceView.swift in Sources */,
D7F8C0392B60564D0072BFA7 /* AddFeaturesWithContingentValuesView.swift in Sources */,
00F279D62AF418DC00CECAF8 /* AddDynamicEntityLayerView.VehicleCallout.swift in Sources */,
10CFF50B2DC2EC990027F144 /* ApplyClassBreaksRendererToSublayerView.swift in Sources */,
D7749AD62AF08BF50086632F /* FindRouteInTransportNetworkView.Model.swift in Sources */,
D73F06692B5EE73D000B574F /* QueryFeaturesWithArcadeExpressionView.swift in Sources */,
D7464F1E2ACE04B3007FEE88 /* IdentifyRasterCellView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2025 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 ArcGIS
import SwiftUI

struct ApplyClassBreaksRendererToSublayerView: View {
/// The map image layer.
@State private var mapImageLayer = ArcGISMapImageLayer(url: URL(string: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer")!)

/// The counties sublayer.
@State private var countiesSublayer: ArcGISMapImageSublayer?

/// The original renderer used to symbolize the sublayer.
@State private var originalRenderer: Renderer?

/// A Boolean value indicating that the class breaks renderer is applied.
@State private var classBreaksRendererIsApplied = false

/// The map with a topographic basemap style.
@State private var map: Map = {
let map = Map(basemapStyle: .arcGISTopographic)

// Sets the initial viewpoint.
map.initialViewpoint = Viewpoint(
boundingGeometry: Envelope(
xMin: -13934661.666904,
yMin: 331181.323482,
xMax: -7355704.998713,
yMax: 9118038.075882,
spatialReference: .webMercator
)
)
return map
}()

/// The error shown in the error alert.
@State private var error: Error?

var body: some View {
MapView(map: map)
.task {
// Adds the map image layer to the map.
map.addOperationalLayer(mapImageLayer)
do {
// Loads the map image layer.
try await mapImageLayer.load()
// Gets the sublayers.
let mapImageSublayers = mapImageLayer.mapImageSublayers
// Gets the third sublayer.
let sublayer = mapImageSublayers[2]
// Loads the sublayer.
try await sublayer.load()
countiesSublayer = sublayer
originalRenderer = sublayer.renderer
} catch {
self.error = error
}
}
.toolbar {
ToolbarItem(placement: .bottomBar) {
Toggle("Change Sublayer Renderer", isOn: $classBreaksRendererIsApplied)
.disabled(countiesSublayer == nil)
}
}
.onChange(of: classBreaksRendererIsApplied) {
countiesSublayer?.renderer = if classBreaksRendererIsApplied {
// Applies the class breaks renderer.
.populationRenderer
} else {
// Applies the original renderer.
originalRenderer
}
}
.errorAlert(presentingError: $error)
}
}

private extension Renderer {
/// Creates a class breaks renderer for counties in the US based on their
/// population in 2007.
static var populationRenderer: ClassBreaksRenderer {
// Outline symbol.
let lineSymbol = SimpleLineSymbol(style: .solid, color: UIColor(white: 0.6, alpha: 1), width: 0.5)

// Symbol for each class break.
let symbol1 = SimpleFillSymbol(style: .solid, color: UIColor(red: 0.89, green: 0.92, blue: 0.81, alpha: 1), outline: lineSymbol)
let symbol2 = SimpleFillSymbol(style: .solid, color: UIColor(red: 0.59, green: 0.76, blue: 0.75, alpha: 1), outline: lineSymbol)
let symbol3 = SimpleFillSymbol(style: .solid, color: UIColor(red: 0.38, green: 0.65, blue: 0.71, alpha: 1), outline: lineSymbol)
let symbol4 = SimpleFillSymbol(style: .solid, color: UIColor(red: 0.27, green: 0.49, blue: 0.59, alpha: 1), outline: lineSymbol)
let symbol5 = SimpleFillSymbol(style: .solid, color: UIColor(red: 0.16, green: 0.33, blue: 0.47, alpha: 1), outline: lineSymbol)

// Class breaks.
let classBreak1 = ClassBreak(description: "-99 to 8,560", label: "-99 to 8,560", minValue: -99, maxValue: 8_560, symbol: symbol1)
let classBreak2 = ClassBreak(description: "> 8,560 to 18,109", label: "> 8,560 to 18,109", minValue: 8_561, maxValue: 18_109, symbol: symbol2)
let classBreak3 = ClassBreak(description: "> 18,109 to 35,501", label: "> 18,109 to 35,501", minValue: 18_110, maxValue: 35_501, symbol: symbol3)
let classBreak4 = ClassBreak(description: "> 35,501 to 86,100", label: "> 35,501 to 86,100", minValue: 35_502, maxValue: 86_100, symbol: symbol4)
let classBreak5 = ClassBreak(description: "> 86,100 to 10,110,975", label: "> 86,100 to 10,110,975", minValue: 86_101, maxValue: 10_110_975, symbol: symbol5)

return ClassBreaksRenderer(fieldName: "POP2007", classBreaks: [classBreak1, classBreak2, classBreak3, classBreak4, classBreak5])
}
}

#Preview {
ApplyClassBreaksRendererToSublayerView()
}
40 changes: 40 additions & 0 deletions Shared/Samples/Apply class breaks renderer to sublayer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Apply class breaks renderer to sublayer

Apply a renderer to a sublayer.

![Image of Apply class breaks renderer to sublayer sample](apply-class-breaks-renderer-to-sublayer.png)

## Use case

A layer showing animal populations contains sublayers for different species. A renderer could be applied which gives each sublayer a different color, so that populations of each species can be compared visually.

## How to use the sample

Wait for the map image layer to load. Tap the 'Change Sublayer Renderer' button to apply a unique value renderer to see different population ranges in the counties sub-layer data.

## How it works

1. Create an `ArcGISMapImageLayer` from its URL.
2. After it is done loading, get its map image sublayers.
3. Get the `MapImageSublayer` you want.
4. Create a `ClassBreaksRenderer` with a collection of `ClassBreak`s for different population ranges.
5. Set class breaks renderer as the renderer of the sublayer.

## Relevant API

* ArcGISMapImageLayer
* ArcGISMapImageSubLayer
* ClassBreak
* ClassBreaksRenderer

## About the data

This application displays census data from an ArcGIS Server map service. It contains various population statistics, including total population for each county in 2007.

## Additional information

The service hosting the layer must support dynamic layers to be able to change the rendering of sublayers.

## Tags

class breaks, dynamic layer, dynamic rendering, renderer, sublayer, symbology, visualization
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"category": "Visualization",
"description": "Apply a renderer to a sublayer.",
"ignore": false,
"images": [
"apply-class-breaks-renderer-to-sublayer.png"
],
"keywords": [
"class breaks",
"dynamic layer",
"dynamic rendering",
"renderer",
"sublayer",
"symbology",
"visualization",
"ArcGISMapImageLayer",
"ArcGISMapImageSubLayer",
"ClassBreak",
"ClassBreaksRenderer"
],
"redirect_from": [],
"relevant_apis": [
"ArcGISMapImageLayer",
"ArcGISMapImageSubLayer",
"ClassBreak",
"ClassBreaksRenderer"
],
"snippets": [
"ApplyClassBreaksRendererToSublayerView.swift"
],
"title": "Apply class breaks renderer to sublayer"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading