Create a Custom Panel Container
The TomTom Digital Cockpit SDK is not available for general use.
Please contact us for more information.
Knowledge of the system UI will help you to understand this guide. If you are not yet familiar with it, feel free to take a look at the system UI overview.
System UI in the TomTom Digital Cockpit visualizes data represented by
Panel
s. How panels are positioned relative to each
other, how they are animated or if they can be dismissed - all this coordination is defined by
the PanelContainer
which displays the concrete
Panel
. The closest counterpart of a PanelContainer
in Android OS is a
ViewGroup
.
In fact, all PanelContainer
s that come with TomTom Digital Cockpit are
based on
ViewGroup
and implement the
PanelContainer
interface. You can see all
PanelContainer
s used by stock system UI in the package
com.tomtom.ivi.platform.systemui.api.common.systemuihost.panelcontainer
.
This example shows how to create a custom PanelContainer
to display two
CustomPanel
s
side-by-side.
This tutorial only describes how to create the custom
PanelContainer
, creation of customPanel
types is described in the Custom Panel Type example.
Create a data class to represent two panels
1internal data class DualPanelContainerData(2 val panel1: Panel,3 val panel2: Panel4)
Create a custom panel container
Create a
DualPanelContainer
with StateDrivenPanelContainer
as a superclass.
1internal class DualPanelContainer @JvmOverloads constructor(2 context: Context,3 attrs: AttributeSet? = null,4 defStyleAttr: Int = 05) :6 StateDrivenPanelContainer<7 DualPanelContainerData?,8 DualPanelSubContainerViewModel,9 DualPanelContainerData>(10 context,11 attrs,12 defStyleAttr13 ) {14 override fun createSubContainerController() =15 DualPanelSubContainerController(ttiviSubContainerLayoutId)1617 override fun createSubContainerViewModel() =18 DualPanelSubContainerViewModel()19}
Create a sub-container view model
Create a
DualPanelSubContainerViewModel
with PanelSubContainerViewModel
as a superclass. Note that the custom data
type, which was created in the first step is used as a type parameter of the generic
PanelSubContainerViewModel
.
1internal class DualPanelSubContainerViewModel :2 PanelSubContainerViewModel<DualPanelContainerData>() {34 internal val panelFragmentContainer1Id:5 PanelFragmentContainerId by generatePanelFragmentContainerId()67 internal val panelFragmentContainer2Id:8 PanelFragmentContainerId by generatePanelFragmentContainerId()9}
Create a sub-container controller
Create a
DualPanelSubContainerController
with StateDrivenSubContainerController
as a superclass.
This is the class where the custom data type DualPanelContainerData
is bound to views on the
screen and updates of data are handled. All generic code for all sub-containers resides in the
superclass, the custom panel container must implement these abstract methods:
getNewSubContainerData()
to determine when new sub-containers must be created.
1 override fun getNewSubContainerData(2 panelContainerViewModel: DualPanelContainerViewModel3 ) = listOfNotNull(4 panelContainerViewModel5 .panelContainerData6 ?.takeUnless { panelContainerViewModel.hasSubContainerViewModelWithData(it) }7 )
createSubContainer()
to inflate sub-container's layout and bind the data model to its views.
1 override fun createSubContainer(2 panelContainer: ViewGroup,3 subContainerViewModel: DualPanelSubContainerViewModel,4 panelContainerViewModel: DualPanelContainerViewModel5 ): StateDrivenSubContainerController.SubContainerCreationResult<6 DualPanelSubContainerViewModel,7 DualPanelContainerData8 > {910 val subContainerHolder = inflateSubContainerAndBindViewModel(11 panelContainer,12 subContainerLayoutId,13 subContainerViewModel14 )1516 val panelFragment1Holder = subContainerHolder.findPanelFragmentContainerAndSetId(17 subContainerViewModel.panelFragmentContainer1Id,18 R.id.ttivi_custompanelcontainer_panel_119 )2021 val panelFragment2Holder = subContainerHolder.findPanelFragmentContainerAndSetId(22 subContainerViewModel.panelFragmentContainer2Id,23 R.id.ttivi_custompanelcontainer_panel_224 )2526 val panelFragmentAdapterBuilder: PanelFragmentAdapterBuilder.() -> Unit = {27 createSingleFragmentPanelAdapter(panelFragment1Holder) {28 SinglePanelAttachment(subContainerViewModel.subContainerData.panel1) { it }29 }3031 createSingleFragmentPanelAdapter(panelFragment2Holder) {32 SinglePanelAttachment(subContainerViewModel.subContainerData.panel2) { it }33 }34 }3536 return StateDrivenSubContainerController.SubContainerCreationResult(37 subContainerHolder,38 panelFragmentAdapterBuilder39 )40 }
getSubContainerDataUpdates()
to determine if data represented by sub-container has changed.
1 override fun getSubContainerDataUpdates(2 panelContainerViewModel: DualPanelContainerViewModel3 ): Collection<StateDrivenSubContainerController.SubContainerDataUpdate<4 DualPanelSubContainerViewModel,5 DualPanelContainerData>6 > {7 val data = panelContainerViewModel.panelContainerData ?: return emptyList()8 val subContainerViewModel = panelContainerViewModel9 .subContainerViewModels10 .firstOrNull() ?: return emptyList()1112 val update = StateDrivenSubContainerController.SubContainerDataUpdate(13 subContainerViewModel,14 data15 )1617 return listOf(update)18 }
The complete code of the
DualPanelSubContainerController
can be found in the
GitHub.
See the custom panel container
After the application is built and deployed to a target device, the custom panel container is displayed on the screen.