These charts are implemented in the sample app.
Vico is a light and extensible chart library for Jetpack Compose and the view system. It comprises two main modules:
compose(for Jetpack Compose)view(for views)
Vico has a very low number of dependencies, and these two modules don’t depend on each other. Find out how.
As a library compatible with both Compose and views, Vico is quite unique. It doesn’t depend on the interoperability between the two UI systems.
The shared, main logic resides in the core module and depends on the Android SDK. It doesn’t know anything about views or Jetpack Compose. Likewise, view (for views) doesn’t know anything about Jetpack Compose, and compose (for Jetpack Compose) doesn’t know anything about views.
I was a little curious about Jetpack Compose’s internals and how come it is interoperable with views.
“Can you, fairly easily, share the code used to draw on the Canvas between these two UI paradigms?” I asked myself.
The answer is yes. core uses android.graphics.Canvas (also used by views) to draw charts, and androidx.compose.ui.graphics.drawscope.DrawScope (used by Jetpack Compose) exposes android.graphics.Canvas via DrawScope#canvas#nativeCanvas. It’s similar for other APIs, like Path.
This approach encourages a greater level of abstraction and promotes separation of concerns. It also helped make the API highly extensible.
-
Ensure your app’s minimum SDK version is 16 (for
coreandview) or 21 (forcompose,compose-m2, andcompose-m3). This is declared in the module-levelbuild.gradlefile.android { defaultConfig { minSdk 16 // Or 21 for Jetpack Compose. ... } ... } -
Ensure the
mavenCentral()repository is declared in the project-levelbuild.gradlefile:allprojects { repositories { mavenCentral() ... } ... } -
Declare the dependencies you need in the module-level
build.gradlefile. All modules depend onvico.core, so you don’t need to add it as a dependency.dependencies { // Provides the utilities needed to use Vico in the view system. implementation "com.patrykandpatryk.vico:view:1.4.3" // Provides the utilities needed to use Vico in Jetpack Compose. implementation "com.patrykandpatryk.vico:compose:1.4.3" // An optional addition for `vico.compose` that creates a `ChartStyle` based on an M2 Material Theme. implementation "com.patrykandpatryk.vico:compose-m2:1.4.3" // An optional addition for `vico.compose` that creates a `ChartStyle` based on an M3 Material Theme. implementation "com.patrykandpatryk.vico:compose-m3:1.4.3" ... }
The following table outlines the modules included in this library:
| Artifact | Description |
|---|---|
core |
Includes the core logic for charts and other components. All modules depend on core. |
view |
Provides the utilities needed to use Vico in the view system. |
compose |
Provides the utilities needed to use Vico in Jetpack Compose. |
compose-m2 |
An optional addition for compose that creates a ChartStyle based on an M2 Material Theme. |
compose-m3 |
An optional addition for compose that creates a ChartStyle based on an M3 Material Theme. |
Included in this repository is a sample app with multiple charts and two tabs—one for Jetpack Compose, and the other one for the view system. Studying the source code of the app will give you a deep understanding of how to use Vico, including topics such as updating data and customizing charts. All of the charts included in the graphic at the top of this README are implemented in the sample app.
Chart data in Vico is stored in ChartEntryModels. For a static chart, you can create a ChartEntryModel instance via the entryModelOf helper function:
val entryModel = entryModelOf(5f, 15f, 10f, 20f, 10f)This creates a ChartEntryModel that can be used in, for example, a column chart. The chart will have five columns.
In Jetpack Compose, use the Chart composable:
Chart(
chart = columnChart(),
model = entryModel,
startAxis = startAxis(),
bottomAxis = bottomAxis(),
)In the view system, use ChartView:
<com.patrykandpatryk.vico.view.chart.ChartView
android:id="@+id/chart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chart="column"
app:showBottomAxis="true"
app:showStartAxis="true" />findViewById<ChartView>(R.id.chart).model = entryModelFor dynamic data sets, use ChartEntryModelProducer (or ComposedChartEntryModelProducer for
composed charts).
For this example, we’ll use a function that generates a random list of FloatEntry instances. A FloatEntry describes a single chart entry (e.g., a column).
fun getRandomEntries() = List(size = 5) {
25f * Random.nextFloat()
}.mapIndexed { x, y ->
FloatEntry(
x = x.toFloat(),
y = y,
)
}A list returned by this function can be used to initialize a ChartEntryModelProducer, which should happen in the viewmodel:
val producer = ChartEntryModelProducer(getRandomEntries())In Compose, you can once again use the Chart composable, but this time the overload with a chartModelProducer parameter:
Chart(
chart = lineChart(),
chartModelProducer = producer,
startAxis = startAxis(),
bottomAxis = bottomAxis(),
)In the view system, you can connect a chart to a ChartEntryModelProducer as follows:
<com.patrykandpatryk.vico.view.chart.ChartView
android:id="@+id/chart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chartType="column"
app:showBottomAxis="true"
app:showStartAxis="true" />findViewById<ChartView>(R.id.chart).entryProducer = producerWith ChartEntryModelProducer, you can update the data displayed by a chart. For the above example, this would be done as follows:
chartModelProducer.setEntries(getRandomEntries()Differences are animated by default.
You can combine multiple charts into one. This example uses the getRandomEntries function from above.
A composed chart requires a ComposedChartEntryModel.
In the case of static charts, you can directly create a ComposedChartEntryModel instance via the composedChartEntryModelOf helper function.
You can also use the + operator to create a ComposedChartEntryModel out of two ChartEntryModels.
For dynamic composed charts, use ComposedChartEntryModelProducer.
For this example, we’ll use a ComposedChartEntryModelProducer. You can create a ComposedChartEntryModelProducer out of two regular ChartEntryModelProducers:
val firstProducer = ChartEntryModelProducer(getRandomEntries())
val secondProducer = ChartEntryModelProducer(getRandomEntries())
val composedProducer = firstProducer + secondProducerA composed chart can be created in Jetpack Compose as follows:
Chart(
chart = lineChart() + columnChart(),
chartModelProducer = composedProducer,
startAxis = startAxis(),
bottomAxis = bottomAxis(),
)And here’s the same chart in the view system. Note that we’re now using ComposedChartView:
<com.patrykandpatryk.vico.view.chart.ComposedChartView
android:id="@+id/chart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chartType="column"
app:showBottomAxis="true"
app:showStartAxis="true"
app:charts="line|column" />findViewById<ComposedChartView>(R.id.chart).entryProducer = composedProducerVico offers rich options for customization and an extensible API. The following resources are available to help you learn about it:
- The sample app contains a full implementation of Vico.
- The wiki describes core topics and includes a detailed customization guide.
- The API reference describes every public class, function, and field.
