LogoLogo
CMSGitHubSupportBook a demo
  • Documentation
  • Academy
  • Help Center
  • Welcome
  • SDKS & Frameworks
    • Web
      • Getting Started
        • Prerequisites
          • MapsIndoors
          • Map Engine Provider
            • Option 1: Get your Mapbox Access Token
            • Option 2: Get your Google Maps API Keys​
          • Map Engine Setup
        • Getting Started: MapsIndoors
      • Map Visualization
        • Highlight, Hover and Select
        • Remove Labels from Buildings and Venues
        • Change Building Outline
        • Managing Collisions Based on Zoom Level
        • 3D Maps
          • Managing your 3D Maps
        • Base Map Styling - Google Maps
        • Managing feature visibility for Mapbox
      • Wayfinding
        • Directions
        • Directions Service
          • Tailoring the directions to your specific needs
        • Directions Renderer
          • Customizing the Route Animation
        • Multi-stop navigation
          • Custom Icons
        • User's Location as Point of Origin
      • Search
        • Search Operations
        • Searching
        • Using External ID, Geospatial Joins
        • Utilizing MapsIndoors Web Components and Other Searches
      • Map Management
      • Data Visualization
        • Display Heatmap Overlay
      • Other guides
        • Authentication
          • Single Sign-On
            • SSO Configuration
            • SSO Authorisation
          • 2-Factor Authentication
          • Password Reset
        • Application User Roles
        • Custom Properties
        • Display Language
        • Language
        • User Positioning
          • Show User's Location aka. Blue Dot
          • Using Cisco DNA Spaces
        • Working with Events
        • Turn Off Collisions Based on Zoom Level
        • Remove Labels from Buildings and Venues for Web
        • Synchronizing data for a subset of venues
        • Custom Floor Selector
      • Display Rules in Practice
      • Offline Data
      • Managing map visibility
    • Android
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
        • Enable Live Data
        • Integrating MapsIndoors into your own App
        • Migrating from V3 to V4
          • Migrating to Mapbox V11
      • Directions
        • Directions Service
        • Directions Renderer
          • User's Location as Point of Origin
        • Wayfinding Instructions
          • See Route Element Details
        • Using multi-stop navigation
      • Searching
        • Searching on a Map
        • Creating a Search Experience
      • Switching Solutions
      • Caching & Offline Data
      • Display Language
      • Displaying Objects
        • Application User Roles
        • Getting a Polygon from a Location
        • Location Clustering
        • Location Data Sources
        • Location Details
        • Turn Off Collisions Based on Zoom Level
        • Enabling and Disabling features on the map
      • Change Building Outline Color
      • Event Logging
      • Configuring a menu with AppConfig
      • Display Heatmap Overlay
      • Custom Properties
      • Custom Floor Selector
      • External IDs
      • User Positioning
        • Show User's Location aka. Blue Dot
        • Using Cisco DNA Spaces
        • Using Google Fused Location Provider
        • Using Indoor Atlas
      • Authentication
        • Single Sign-On
          • SSO Configuration
          • SSO Authorisation
        • 2-Factor Authentication
        • Password Reset
      • Display Rules in Practice
        • Label styling through Display Rules
      • Highlight and Select
    • iOS
      • Getting Started
        • Prerequisites
        • Set Up Your Environment
        • Display a Map
        • Search
        • Getting Directions
        • Migrating from v3 to v4
      • Directions
        • Directions Renderer
          • User's Location as Point of Origin
        • Wayfinding Instructions
          • See Route Element Details
        • Directions Service
        • Using multi-stop navigation
      • Searching
        • Searching on a Map
        • Creating a Search Experience
      • Caching & Offline Data
      • Displaying Objects
        • Application User Roles
        • Getting a Polygon from a Location
        • Location Details
        • Turn Off Collisions Based on Zoom Level
        • Enabling and Disabling features on the map
      • Custom Floor Selector
      • Change Building Outline Color
      • Custom Map Padding
      • Custom Properties
      • Display Rules in Practice
        • Label styling through Display Rules
      • Switching Solutions
      • Show User's Location aka. Blue Dot
        • Using Indoor Atlas
        • Using Cisco DNA Spaces
      • Highlight and Select
      • Display Language
    • React Native
      • Getting Started
        • Prerequisites
        • Project Setup
        • Displaying a Map
        • Creating a Search Experience
        • Getting Directions
        • Enabling Live Data
      • Showing Blue Dot
    • Flutter
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
      • Migration Guide
    • Integration API
      • Integration API Access
        • Access with Swagger
        • Access with Postman
        • Access with Python
        • Client credentials flow
      • Data Description
      • Reverse Geocoding
      • Route Access
      • OpenAPI Specification
    • Built-In Map Edits
      • Getting started
      • Authentication
      • Release notes
      • Reference docs
  • Products
    • Product Overview
    • CMS
      • Interface Overview
      • Display Rules
      • Media Library
        • 2D Models and Icons
        • 3D Models
      • Editing Data
      • Solution Settings
      • Settings
      • Data Concepts
      • User Roles
      • Route Network
        • Barrier Route Element
        • Door Route Element
      • Additional Location Details
    • Map Template
      • Getting Started
        • Web Component
        • React Component
      • Configuration
        • Query Parameters
      • Customization
      • Deploying Map Template to a cloud storage provider
      • 2D/3D Visibility Switch
      • External customization of the Map Template
      • Location Details configuration
      • Kiosk
        • QR code configuration
  • Other
    • Design
      • Standard MapsIndoors Map Style
      • Using a Custom Mapbox MapStyle
    • Changelog
      • Web SDK
        • V4
        • V3
      • Android SDK
        • V4
        • V3
      • iOS SDK
        • V4
        • V3
      • React Native SDK
      • Flutter SDK
      • MI Components
      • Map Template
    • Glossary
  • Legacy Docs
    • Android SDK V3
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
        • Enable Live Data
        • Integrating MapsIndoors into your own App
    • iOS SDK V3
      • Getting Started
        • Prerequisites
        • Set Up Your Environment
        • Display a Map
        • Search
        • Directions
        • Live Data
        • Integrating MapsIndoors into your own App
      • Inspect Route Element for iOS v3
      • Using Cisco DNA Spaces
      • Using Indoor Atlas
      • Switching Solutions
      • Show User's Location aka. Blue Dot
      • Application User Roles
      • Getting a Polygon from a Location
      • Location Details
  • MapsIndoors SDK Firewall
  • Google Analytics & Logging
  • Reference Docs
    • Web SDK
    • Android SDK
    • iOS SDK
    • React Native SDK
    • Flutter SDK
Powered by GitBook
On this page

Was this helpful?

Export as PDF
  1. SDKS & Frameworks
  2. Android

Custom Floor Selector

Last updated 5 months ago

Was this helpful?

How to implement a custom floor selector

To implement a custom floor selector we expect you to already have a View with a Map using MapControl.

Start by creating a class, in this example named; CustomFloorSelector. Extend the class with FrameLayout and implement MPFloorSelectorInterface as well as it's methods.

    class CustomFloorSelector(private val context: Context, attrs: AttributeSet): MPFloorSelectorInterface, FrameLayout(context, attrs)  {
        override fun getView(): View? {
            TODO("Not yet implemented")
        }

        override fun setOnFloorSelectionChangedListener(listener: OnFloorSelectionChangedListener?) {
            TODO("Not yet implemented")
        }

        override fun setList(floors: MutableList<MPFloor>?) {
            TODO("Not yet implemented")
        }

        override fun show(show: Boolean, animated: Boolean) {
            TODO("Not yet implemented")
        }

        override fun setSelectedFloor(floor: MPFloor) {
            TODO("Not yet implemented")
        }

        override fun setSelectedFloorByZIndex(zIndex: Int) {
            TODO("Not yet implemented")
        }

        override fun zoomLevelChanged(newZoomLevel: Float) {
            TODO("Not yet implemented")
        }

        override fun isAutoFloorChangeEnabled(): Boolean {
            TODO("Not yet implemented")
        }

        override fun setUserPositionFloor(zIndex: Int) {
            TODO("Not yet implemented")
        }
    }

We also need to implement a simple view to show the current floor and allow the user to select another floor. We will do this by creating a simple Button that when clicked creates a drop down allowing the user to select any floor.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="40dp"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <Button
        android:id="@+id/custom_floor_selector_btn"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1"/>
</androidx.constraintlayout.widget.ConstraintLayout>

We can now start implementing logic into our CustomFloorSelector class. We will start by implementing the methods from the MPFloorSelectorInterface. We start by adding a HashMap<Int, MPFloor> to the class to keep track of the current floors. We populate the list when setList is called. We add a OnFloorSelectionChangedListener, so that we can notify when floors have changed in the UI. For the show we will ignore the animated bool, to keep it simple and we just toggle the visibility for this example. We will ignore the zoomLevelChanged method in this example, but it allows you to implement logic in the custom floor selector based on the current zoom level. For this example we will allow AutoFloorChanges, the setUserPositionFloor can be used to keep track of the current floor of the user, if using any type of indoor positioning service, together with MapsIndoors. For this example, we will save the user location, but will not add any logic based on it.

class CustomFloorSelector(private val context: Context, attrs: AttributeSet): MPFloorSelectorInterface, FrameLayout(context, attrs)  {
    private var floorMap: HashMap<Int, MPFloor> = HashMap()
    private var mOnFloorSelectionChangedListener: OnFloorSelectionChangedListener? = null

    ...
    override fun setList(floors: MutableList<MPFloor>?) {
        floorMap.clear()
        floors?.forEach {
            floorMap[it.floorIndex] = it
        }
    }

    override fun setOnFloorSelectionChangedListener(listener: OnFloorSelectionChangedListener?) {
        mOnFloorSelectionChangedListener = listener
    }

    override fun show(show: Boolean, animated: Boolean) {
        visibility = if (show) View.VISIBLE else View.GONE
    }

    override fun zoomLevelChanged(newZoomLevel: Float) {
        //ignore
    }

    override fun isAutoFloorChangeEnabled(): Boolean {
        return true
    }

    override fun setUserPositionFloor(zIndex: Int) {
        mUserFloorIndex = zIndex
    }
    ...
}

For the remaining methods we need to modify the UI, so we will start implementing the UI first. Inside the init we will inflate the view and store and hold a reference to it, to return inside the getViewmethod. We will also create a reference to the Button that we implemented. The floorBtn needs to open a dropdown when clicked we will do this with a PopupMenu that is ordered by the floor index. When a MenuItem is clicked we use the itemId to retrieve the correct floor from the floor map. When that is retrieved we update the floorBtn text, for the now selected floor, as well as calling onFloorSelectionChanged with the selected floor. For the map to update and reflect the action.

class CustomFloorSelector(private val context: Context, attrs: AttributeSet): MPFloorSelectorInterface, FrameLayout(context, attrs)  {
    ...
    
    private var floorBtn: Button? = null
    private var mView: View? = null
    private var mSelectedFloor: MPFloor? = null
    ...

    init {
        mView = inflate(context, R.layout.custom_floor_selector, this)
        floorBtn = findViewById(R.id.custom_floor_selector_btn)

        floorBtn?.setOnClickListener { it ->
            val popup = PopupMenu(context, it)
            floorMap.values.forEach {
                popup.menu.add(0,it.floorIndex, it.floorIndex, it.displayName)
            }
            popup.show()
            popup.setOnMenuItemClickListener { menuItem ->
                val floor = floorMap[menuItem.itemId]
                floor?.let {
                    floorBtn?.text = it.displayName
                    mOnFloorSelectionChangedListener?.onFloorSelectionChanged(it)
                }
                popup.dismiss()
                return@setOnMenuItemClickListener true
            }
        }
    }

    override fun getView(): View? {
        return mView
    }

    override fun setSelectedFloor(floor: MPFloor) {
        mSelectedFloor = floor
        floorBtn?.text = floor.displayName
    }

    override fun setSelectedFloorByZIndex(zIndex: Int) {
        mSelectedFloor = floorMap[zIndex]
        floorBtn?.text = floorMap[zIndex]?.displayName
    }
}

Now all that is left is adding this view component to your layout containing the map and adding it to your MPMapConfig when creating MapControl. Here is an example layout where the floor selector is added to a layout.

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/map_fragment"
        android:name="com.mapsindoors.testapp.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <com.mapsindoors.testapp.CustomFloorSelector
        android:id="@+id/custom_floor_selector"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
fun initMapControl() {
    floorSelector = findViewById(R.id.custom_floor_selector)
    val mapConfig = MPMapConfig.Builder(
            requireActivity(),
            mMap,
            mMapView,
            getString(R.string.mapbox_api_key),
            true).setFloorSelector(floorSelector).build()
    MapControl.create(mapConfig) { mapControl: MapControl?, miError: MIError? ->
    }
}

You have now succesfully implemented a custom floor selector into your own app.

Show a map