Overview

You will learn: how to apply symbol colors and styles to features based on attribute values.

With the ArcGIS Runtime SDK for Java you can apply custom symbol colors and styles to improve the visualization of feature layers by defining a Renderer. The first step is to define the renderer symbols, colors, and field values, and then apply it to the layer. The renderer is responsible for applying the symbols to appropriate elements when the layer draws. There are many different types of symbols and renderers to choose from. Please visit the symbols and renderers documentation to learn more.

In this lab you will apply different renderers to the trailheads (points), trails (lines), and open spaces (polygon) feature layers.

Steps

Reuse the starter project

If you have not done the starter project lab, be sure to review it first so you are familiar with running the app.

In a new or empty folder, make a copy of the Create a starter app solution.

Update the project

  1. Open the settings.gradle file in an editor of your choice and change the rootProject.name value to style-feature-layers.

Imports and variable declarations

  1. Open the App.java file in src/main/java/com/arcgis/developers/labs. Then merge the following with the existing imports.

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    import com.esri.arcgisruntime.data.ServiceFeatureTable;
    import com.esri.arcgisruntime.layers.FeatureLayer;
    import com.esri.arcgisruntime.symbology.ClassBreaksRenderer;
    import com.esri.arcgisruntime.symbology.ClassBreaksRenderer.ClassBreak;
    import com.esri.arcgisruntime.symbology.PictureMarkerSymbol;
    import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleRenderer;
    import com.esri.arcgisruntime.symbology.UniqueValueRenderer;
    import com.esri.arcgisruntime.symbology.UniqueValueRenderer.UniqueValue;
    
  2. Setting up fields for color constants to represent ARGB hexidecimals.

    /* ** ADD ** */
    private final int hexRed = 0xFFFF0000;
    private final int hexBlue = 0xFF0000FF;
    private final int hexGreen = 0xFF00FF00;
    private final int hexPurple = 0xFF551A8B;
    private final int hexBlack = 0xFF000000;
    private final int hexOrange = 0xFFFFA500;
    /* ** ADD ** */
    
    private MapView mapView;
    

Create method for adding layers

  1. Add a method addFeatureLayerthat creates a FeatureLayer from a ServiceFeatureTable and adds it to the map.

    private FeatureLayer addFeatureLayer(String uri) {
    
      ServiceFeatureTable serviceFeatureTable = new ServiceFeatureTable(uri);
      FeatureLayer featureLayer = new FeatureLayer(serviceFeatureTable);
      ArcGISMap map = mapView.getMap();
      map.getOperationalLayers().add(featureLayer);
    
      return featureLayer;
    }
    

Display features in the Trailheads layer with an image (picture marker symbol)

  1. Add a method addTrailheadsLayer that creates a feature layer for Los Angeles trailheads.

    private void addTrailheadsLayer() {
      String url = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads/FeatureServer/0";
      FeatureLayer featureLayer = addFeatureLayer(url);
    }
    
  2. Create a PictureMarkerSymbol and apply it as a renderer to that layer.

    FeatureLayer featureLayer = addFeatureLayer(url);
    
    /* ** ADD ** */
    String pictureURI = "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png";
    PictureMarkerSymbol pictureMarkerSymbol = new PictureMarkerSymbol(pictureURI);
    SimpleRenderer simpleRenderer = new SimpleRenderer(pictureMarkerSymbol);
    featureLayer.setRenderer(simpleRenderer);
    
  3. Add method addTrailheadsLayer to start method.

    setupMap();
    
    /* ** ADD ** */
    addTrailheadsLayer();
    

Style the Trails layer by unique values

  1. Add method addTrailsLayer that creates a feature layer of Los Angeles trails.

    private void addTrailsLayer() {
    
      String url = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0";
      FeatureLayer featureLayer = addFeatureLayer(url);
    }
    
  2. Create a UniqueValueRenderer with ("USE_BIKE") field and set it to the feature layer.

    FeatureLayer featureLayer = addFeatureLayer(url);
    
    /* ** ADD ** */
    UniqueValueRenderer trailsUniqueValueRenderer = new UniqueValueRenderer();
    trailsUniqueValueRenderer.getFieldNames().add("USE_BIKE");
    featureLayer.setRenderer(trailsUniqueValueRenderer);
    
  3. Create symbols for trails that allow bikes and those that don't.

    featureLayer.setRenderer(trailsUniqueValueRenderer);
    
    /* ** ADD ** */
    SimpleLineSymbol bikeTrailSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.DOT, hexBlue, 2.0f);
    SimpleLineSymbol noBikeTrailSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.DOT, hexRed, 2.0f);
    UniqueValue trailsForBike = new UniqueValue("Bike trails", "Bike", bikeTrailSymbol, Arrays.asList("Yes"));
    UniqueValue trailsNoBike = new UniqueValue("No bike trails", "No Bike", noBikeTrailSymbol, Arrays.asList("No"));
    trailsUniqueValueRenderer.getUniqueValues().add(trailsForBike);
    trailsUniqueValueRenderer.getUniqueValues().add(trailsNoBike);
    
  4. Add method addTrailheadsLayer to start method.

    setupMap();
    
    /* ** ADD ** */
    addTrailsLayer();
    /* ** ADD ** */
    addTrailheadsLayer();
    

Style the Parks and Open Spaces layer by numeric values

  1. Add method addOpenSpaceLayer that creates a feature layer of Los Angeles parks and open space.

     private void addOpenSpaceLayer() {
    
       String openSpacesFeaturesUrl =
           "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space/FeatureServer/0";
       FeatureLayer featureLayer = addFeatureLayer(openSpacesFeaturesUrl);
     }
    
  2. Create fill symbols for three classes of open space area. Each fill symbol uses the same outline symbol and solid fill, but has a different color.

     FeatureLayer featureLayer = addFeatureLayer(openSpacesFeaturesUrl);
    
     /* ** ADD ** */
     SimpleLineSymbol fillOutlineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, hexBlack, 0.5f);
     SimpleFillSymbol greenClassSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, hexGreen, fillOutlineSymbol);
     SimpleFillSymbol purpleClassSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, hexPurple, fillOutlineSymbol);
     SimpleFillSymbol orangeClassSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, hexOrange, fillOutlineSymbol);
    
  3. Create three ClassBreaks based on ranges of open space area. Assign a different fill symbol for each class, provide a description and label, and define the minimum and maximum values for each range. Add the class breaks to a list.

     SimpleFillSymbol orangeClassSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, hexOrange, fillOutlineSymbol);
    
     /* ** ADD ** */
     ClassBreak greenClassBreak = new ClassBreak("Under 1,629", "0 - 1629", 0.0, 1629.0, greenClassSymbol);
     ClassBreak purpleClassBreak = new ClassBreak("1,629 to 3,754", "1629 - 3754", 1629.0, 3754.0, purpleClassSymbol);
     ClassBreak orangeClassBreak = new ClassBreak("3,754 to 11,438", "3754 - 11438", 3754.0, 11438.0, orangeClassSymbol);
    
     List<ClassBreak> acreageBreaks = new ArrayList<>();
     acreageBreaks.add(greenClassBreak);
     acreageBreaks.add(purpleClassBreak);
     acreageBreaks.add(orangeClassBreak);
    
  4. Create the ClassBreakRenderer on the "GIS_ACRES" field with the list of breaks. Assign this renderer to the feature layer.

     acreageBreaks.add(orangeClassBreak);
     /* ** ADD ** */
     ClassBreaksRenderer openSpacesClassBreaksRenderer = new ClassBreaksRenderer("GIS_ACRES", acreageBreaks);
     featureLayer.setRenderer(openSpacesClassBreaksRenderer);
    
  5. Add method addOpenSpaceLayer to start method.

     setupMap();
    
     /* ** ADD ** */
     addOpenSpaceLayer();
     /* ** ADD ** */
     addTrailsLayer();
    

Congratulations, you're done!

Run your app to test your code. When the app opens, you should see trailheads symbolized with a picture marker, trails symbolized according to accessibility by bikes, and open spaces according to acreage.

Check out and compare with our completed solution project.

Challenge

Explore multiple unique values

A UniqueValueRenderer can use more than one field to define unique values to display. The Trails layer was rendered with values in "USE_BIKE". The feature table, however, has additional fields to describe if the trail allows pets ("PET_ACC"), horses ("USE_EQU"), or all-terrain vehicles ("USE_ATV"). Experiment with rendering the trails layer with UniqueValues that are combinations of values from these attributes (trails that allow both bikes and pets, for example).