intermediate
Java
Runtime styling for Android
Prerequisite
An Android application with a simple map view set up and familiarity with Android Studio and Java.

Runtime styling is a powerful feature within the Mapbox Maps SDK for Android, which enables you to change the map’s properties in real time, allowing you to customize every aspect of the map’s appearance down to the smallest detail.

In this tutorial, you’ll build a map for Android that changes the fill color of the earth’s water and changes several text properties (size, color, halo blur, etc.) of marine labels.

map with water fill color and marine label texts updated on an Android device

Getting started

This guide assumes that you are familiar with Java and Android Studio. Here are the resources that you’ll need before getting started:

  • A Mapbox account and access token. Sign up for an account at mapbox.com/signup. You can find your access tokens on your Account page. You will add your access token to your strings.xml file.

  • An application including the Mapbox Maps SDK for Android. This guide also assumes that you have already begun building an Android application that uses the Mapbox Maps SDK for Android. If you’re new to the Maps SDK for Android, check out the First steps with the Mapbox Maps SDK for Android guide to set up a simple map view first.

Initialize a MapView

Start by creating a new project in Android Studio and initializing a MapView. There are five files that you’ll be working with in your Android Studio project to set up a Mapbox map and use runtime styling to change the map’s appearance. The five files you’ll be working with are:

  • build.gradle
  • AndroidManifest.xml
  • activity_main.xml
  • strings.xml
  • MainActivity.java

Android Studio uses a toolkit called Gradle to compile resources and source code into an APK. The build.gradle file is used to configure the build and list dependencies, including the Mapbox Maps SDK for Android. In your build.gradle file, add Mapbox as a dependency:

build.gradle
// in addition to the rest of your build.gradle contents
// you should include the following repository and dependency

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.android.support:design:26.1.0'
    implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:6.4.0@aar') {
        transitive = true
    }
}

The AndroidManifest.xml file is where you’ll describe components of the application, including Mapbox-related permissions. In app > manifests > AndroidManifest.xml add the <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> permission:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mapbox.runtimestylingforandroid"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

The activity_main.xml file is where you’ll set the properties for your MapView and where you’ll add a button to the layout. Clicking this button will trigger the runtime styling changes. In app > res > layout > activity_main.xml, specify the center of the map view, the zoom level, and the map style used when the application is initialized:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.mapbox.mapboxsdk.maps.MapView
        android:id="@+id/runtime_mapview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        mapbox:mapbox_cameraTargetLat="19.948045"
        mapbox:mapbox_cameraTargetLng="-84.654463"
        mapbox:mapbox_cameraZoom="3.371717"
        mapbox:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_marginBottom="16dp"
        android:layout_marginEnd="16dp" />

</RelativeLayout>

You’ll store your access token in the strings.xml file. In app > res > values > strings.xml:

strings.xml
<string name="access_token" translatable="false"><your access token here></string>

MainActivity.java is a Java file where you’ll specify Mapbox-specific interactions. In app > java > yourcompany.yourproject > MainActivity.java initialize your map:

MainActivity.java

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;

import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;


public class MainActivity extends AppCompatActivity {

    private MapView mapView;
    private FloatingActionButton myFab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Mapbox.getInstance(this, getString(R.string.access_token));
        setContentView(R.layout.activity_main);
        mapView = (MapView) findViewById(R.id.runtime_mapview);
        mapView.onCreate(savedInstanceState);
        myFab = findViewById(R.id.floatingActionButton);


}

    // Add the mapView's own lifecycle methods to the activity's lifecycle methods
    @Override
    public void onStart() {
        super.onStart();
        mapView.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        mapView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mapView.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
        mapView.onStop();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }
}

More details about setting up an Android Studio project to be used with the Maps SDK for Android can be found in the First steps with the Mapbox Maps SDK for Android guide. Run your application, and you should see a map in the Mapbox Streets style centered on the Gulf of Mexico and Caribbean Sea.

a map centered on the Caribbean with Mapbox Streets style an Android device

Retrieve layers

Next, you’ll use code from the Mapbox Maps SDK for Android to obtain the map’s layers. Manipulating the layers is what leads to the visual changes.

Import classes

First, import the correct classes in the MainActivity.java file. The Layer class is for creating layer objects that will be manipulated later. The PropertyFactory class enables you to change the map layers’ colors and label properties.

MainActivity.java

import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;

Add the following code within the onCreate() method of the MainActivity.java file:

MainActivity.java

mapView.getMapAsync(new OnMapReadyCallback() {
    @Override
    public void onMapReady(final MapboxMap mapboxMap) {
        final Layer waterLayer = mapboxMap.getLayer("water");


}
});

Style the layers

Now you’ll change the color of the water layer and several properties of marine labels text. In this tutorial, the changes will happen when the pink floating action button is clicked.

Import classes

First, import the correct classes in the MainActivity.java file. The View class is for the pink floating action button’s click listener. The Color class lets you use hex color codes to set the new color of the map layers.

MainActivity.java

import android.view.View;
import android.graphics.Color;

Change the water color

Start by adding the floating action button’s click listener below the waterLayer Layer object. Then adjust the water color to a darker blue color inside of the onClick() method.

MainActivity.java

myFab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (waterLayer != null) {
            waterLayer.setProperties(PropertyFactory.fillColor(Color.parseColor("#023689"))
            );
        }


}
});

Rerun your application, click on the pink floating action button, and you will see all of the earth’s water turn to a darker blue color.

a map with dark blue colored water on an Android device

Change marine labels’ text properties

Now specify the new properties of marine labels’ text. In the floating action button’s onClick() method, add the following code to adjust the labels’ halo blur, size, color, and opacity.

MainActivity.java

for (Layer singleMapLayer : mapboxMap.getLayers()) {
    if (singleMapLayer.getId().contains("marine")) {
        singleMapLayer.setProperties(
                PropertyFactory.textHaloBlur(10f),
                PropertyFactory.textSize(25f),
                PropertyFactory.textColor(Color.parseColor("#00FF08")),
                PropertyFactory.textOpacity(1f)
        );
    }
}

The for (Layer singleMapLayer : mapboxMap.getLayers()) line tells the app to check each map layer for the word marine. This is because the word marine is in the Mapbox Streets style’s following layers:

  • marine-label-sm-ln
  • marine-label-sm-pt
  • marine-label-md-ln
  • marine-label-md-pt
  • marine-label-lg-ln
  • marine-label-lg-pt

Using the for loop is a simple way to retrieve these six layers. The for loop is used instead of creating a separate layer object for each marine label layer and then repeating the same text changes to each individual layer. Using a for loop in this way is a great way to change the properties of several layers that have the same word in them. Examples of words that are commonly repeated in layer names are landcover, road, place, and state.

Rerun your application, click on the pink floating action button, and you will see the map’s marine layers’ text become much larger, greener, less opaque, and have a blurrier halo.

map with attribute styled in runtime on an Android device

Finished product

Great work! You’ve created an app that changes the water layer’s fill color and changes several text properties of multiple map layers. These changes didn’t happen because of a particular data set, the pre-made map style, or any other factor. They happened in runtime and on-the-fly!

map with attribute styled in runtime on an Android device

Next steps

There are many possibilities when using runtime styling to create beautiful and informative maps for Android applications. Read more about runtime styling more generally in our Map design guide and dig into some runtime styling examples specifically for Android: