Skip to content

Commit 378a84c

Browse files
authored
Merge pull request #610 from AppDevNext/Compose
Compose
2 parents 5c37994 + 6beb2cb commit 378a84c

32 files changed

Lines changed: 2547 additions & 0 deletions

File tree

COMPOSE_MIGRATION.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# AndroidChart Compose Integration
2+
3+
## Overview
4+
5+
All chart classes from the `info.appdev.charting.charts` package have been successfully converted to Jetpack Compose composables. The implementation uses AndroidView wrappers to provide a Compose-friendly API while maintaining full compatibility with the existing chart rendering engine.
6+
7+
## Usage Examples
8+
9+
### Basic Line Chart
10+
11+
```kotlin
12+
@Composable
13+
fun MyLineChart() {
14+
val entries = remember {
15+
listOf(
16+
Entry(0f, 10f),
17+
Entry(1f, 20f),
18+
Entry(2f, 15f),
19+
Entry(3f, 30f)
20+
)
21+
}
22+
23+
val dataSet = LineDataSet(entries, "Sample Data").apply {
24+
color = Color.BLUE
25+
setDrawCircles(true)
26+
}
27+
28+
val lineData = LineData(dataSet)
29+
30+
LineChart(
31+
data = lineData,
32+
modifier = Modifier
33+
.fillMaxWidth()
34+
.height(300.dp),
35+
description = "Sales Over Time",
36+
animationDuration = 1000,
37+
onValueSelected = { entry, highlight ->
38+
println("Selected: ${entry?.y}")
39+
}
40+
)
41+
}
42+
```
43+
44+
### Bar Chart with Configuration
45+
46+
```kotlin
47+
@Composable
48+
fun MyBarChart() {
49+
val barData = remember { createBarData() }
50+
51+
BarChart(
52+
data = barData,
53+
modifier = Modifier.fillMaxSize(),
54+
description = "Monthly Revenue",
55+
backgroundColor = Color(0xFFF5F5F5),
56+
drawValueAboveBar = true,
57+
animationDuration = 1500,
58+
legend = { legend ->
59+
legend.isEnabled = true
60+
legend.textSize = 12f
61+
},
62+
xAxisConfig = { xAxis ->
63+
xAxis.position = XAxis.XAxisPosition.BOTTOM
64+
xAxis.setDrawGridLines(false)
65+
},
66+
leftAxisConfig = { axis ->
67+
axis.axisMinimum = 0f
68+
}
69+
)
70+
}
71+
```
72+
73+
### Pie Chart with Customization
74+
75+
```kotlin
76+
@Composable
77+
fun MyPieChart() {
78+
val pieData = remember { createPieData() }
79+
80+
PieChart(
81+
data = pieData,
82+
modifier = Modifier
83+
.fillMaxWidth()
84+
.height(400.dp),
85+
drawHoleEnabled = true,
86+
holeRadius = 40f,
87+
transparentCircleRadius = 45f,
88+
centerText = "Total Sales",
89+
rotationEnabled = true,
90+
usePercentValuesEnabled = true,
91+
animationDuration = 1200,
92+
legend = { legend ->
93+
legend.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM
94+
legend.orientation = Legend.LegendOrientation.HORIZONTAL
95+
}
96+
)
97+
}
98+
```
99+
100+
### Combined Chart
101+
102+
```kotlin
103+
@Composable
104+
fun MyCombinedChart() {
105+
val combinedData = remember {
106+
CombinedData().apply {
107+
setData(createLineData())
108+
setData(createBarData())
109+
}
110+
}
111+
112+
CombinedChart(
113+
data = combinedData,
114+
modifier = Modifier.fillMaxSize(),
115+
drawOrder = arrayOf(
116+
CombinedChart.DrawOrder.BAR,
117+
CombinedChart.DrawOrder.LINE
118+
),
119+
description = "Sales and Forecast",
120+
animationDuration = 1000
121+
)
122+
}
123+
```
124+
125+
### Stateful Chart with Updates
126+
127+
```kotlin
128+
@Composable
129+
fun InteractiveLineChart() {
130+
val state = rememberLineChartState()
131+
var selectedValue by remember { mutableStateOf<Float?>(null) }
132+
133+
Column {
134+
LineChart(
135+
data = state.data,
136+
modifier = Modifier
137+
.fillMaxWidth()
138+
.height(300.dp),
139+
state = state,
140+
onValueSelected = { entry, _ ->
141+
selectedValue = entry?.y
142+
}
143+
)
144+
145+
selectedValue?.let { value ->
146+
Text("Selected: $value", modifier = Modifier.padding(16.dp))
147+
}
148+
149+
Button(
150+
onClick = {
151+
state.data = generateNewData()
152+
}
153+
) {
154+
Text("Refresh Data")
155+
}
156+
}
157+
}
158+
```
159+
160+
## Migration from View-Based Charts
161+
162+
### Before (View-Based)
163+
```kotlin
164+
AndroidView(factory = { context ->
165+
LineChart(context).apply {
166+
data = lineData
167+
description.isEnabled = false
168+
setTouchEnabled(true)
169+
animateX(1000)
170+
invalidate()
171+
}
172+
})
173+
```
174+
175+
### After (Compose)
176+
```kotlin
177+
LineChart(
178+
data = lineData,
179+
description = null,
180+
touchEnabled = true,
181+
animationDuration = 1000
182+
)
183+
```
184+
185+
## Implementation Details
186+
187+
### AndroidView Wrapper Pattern
188+
Each composable uses the `AndroidView` wrapper to embed the existing View-based chart implementation. This provides:
189+
- Immediate compatibility with existing rendering code
190+
- Full feature support without rewriting rendering logic
191+
- Efficient integration with Compose's recomposition system
192+
193+
### Lifecycle Management
194+
- `remember {}` - Creates chart instance once
195+
- `DisposableEffect` - Cleans up chart resources on disposal
196+
- `AndroidView.update {}` - Updates chart when parameters change
197+
198+
### Data Flow
199+
1. User provides chart data as composable parameter
200+
2. `update` lambda calls `chart.setData(data)`
201+
3. Chart configuration applied (colors, animations, axes)
202+
4. `chart.invalidate()` triggers redraw
203+
5. Recomposition on parameter changes updates the chart

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies {
5353
implementation("androidx.appcompat:appcompat:1.7.1")
5454
implementation("com.google.android.material:material:1.13.0")
5555
implementation(project(":chartLib"))
56+
implementation(project(":chartLibCompose"))
5657
implementation("androidx.window:window:1.5.1")
5758

5859
// Compose BOM

app/src/androidTest/kotlin/info/appdev/chartexample/StartTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import androidx.test.ext.junit.rules.activityScenarioRule
2525
import androidx.test.ext.junit.runners.AndroidJUnit4
2626
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
2727
import info.appdev.chartexample.compose.HorizontalBarComposeActivity
28+
import info.appdev.chartexample.compose.HorizontalBarFullComposeActivity
2829
import info.appdev.chartexample.fragments.ViewPagerSimpleChartDemo
2930
import info.appdev.chartexample.notimportant.ContentItem
3031
import info.appdev.chartexample.notimportant.DemoBase
@@ -249,6 +250,7 @@ class StartTest {
249250
contentItem.clazz == RealtimeLineChartActivity::class.java ||
250251
contentItem.clazz == LineChartTimeActivity::class.java ||
251252
contentItem.clazz == HorizontalBarComposeActivity::class.java ||
253+
contentItem.clazz == HorizontalBarFullComposeActivity::class.java ||
252254
contentItem.clazz == GradientActivity::class.java ||
253255
contentItem.clazz == TimeLineActivity::class.java
254256
) {

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<activity android:name="info.appdev.chartexample.BarChartActivity" />
2727
<activity android:name="info.appdev.chartexample.HorizontalBarChartActivity" />
2828
<activity android:name="info.appdev.chartexample.compose.HorizontalBarComposeActivity" />
29+
<activity android:name="info.appdev.chartexample.compose.HorizontalBarFullComposeActivity" />
2930
<activity android:name="info.appdev.chartexample.HorizontalBarNegativeChartActivity" />
3031
<activity android:name="info.appdev.chartexample.PieChartActivity" />
3132
<activity android:name="info.appdev.chartexample.PieChartRoundedActivity" />

0 commit comments

Comments
 (0)