A simple yet highly customizable UI library to show a timeline view in Compose Multiplatform.
| Basic | Dashed | Dynamic |
|---|---|---|
![]() |
![]() |
![]() |
| Custom | Extended | |
![]() |
![]() |
| Android | iOS | Desktop | Web |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
In build.gradle of shared module, include the following dependency
dependencies {
implementation("io.github.pushpalroy:jetlime:3.0.1")
}Use the JetLimeColumn
val items = remember { mutableListOf(Item1, Item2, Item3) } // Any type of items
JetLimeColumn(
modifier = Modifier.padding(16.dp),
itemsList = ItemsList(items),
key = { _, item -> item.id },
) { index, item, position ->
JetLimeEvent(
style = JetLimeEventDefaults.eventStyle(
position = position
),
) {
// Content here
}
}Use the JetLimeRow
val items = remember { mutableListOf(Item1, Item2, Item3) } // Any type of items
JetLimeRow(
modifier = Modifier.padding(16.dp),
itemsList = ItemsList(items),
key = { _, item -> item.id },
) { index, item, position ->
JetLimeEvent(
style = JetLimeEventDefaults.eventStyle(
position = position
),
) {
// Content here
}
}Pass the key to define factory of stable and unique keys representing the item. Using the same key for multiple items in the list is not allowed.
This key will be used by a LazyColumn or LazyRow internally.
If we want to add items dynamically from a data source, we should use mutableStateListOf, so that our list can be observed as a state:
val items = remember { mutableStateListOf<MyItem>() }Use the JetLimeExtendedEvent with a JetLimeColumn Using this we can pass an additional content to draw on the left side of the timeline.
val items = remember { mutableListOf(Item1, Item2, Item3) } // Any type of items
JetLimeColumn(
modifier = Modifier.padding(16.dp),
itemsList = ItemsList(items),
key = { _, item -> item.id },
style = JetLimeDefaults.columnStyle(contentDistance = 24.dp),
) { index, item, position ->
JetLimeExtendedEvent(
style = JetLimeEventDefaults.eventStyle(
position = position
),
additionalContent = {
// Additional content here
}
) {
// Content here
}
}Use the JetLimeDefaults.columnStyle()
JetLimeColumn(
style = JetLimeDefaults.columnStyle(
contentDistance = 32.dp,
itemSpacing = 16.dp,
lineThickness = 2.dp,
lineBrush = JetLimeDefaults.lineSolidBrush(color = Color(0xFF2196F3)),
lineVerticalAlignment = RIGHT,
),
) {
// Code to add events
}Use the JetLimeDefaults.rowStyle()
JetLimeRow(
style = JetLimeDefaults.rowStyle(
contentDistance = 32.dp,
itemSpacing = 16.dp,
lineThickness = 2.dp,
lineBrush = JetLimeDefaults.lineSolidBrush(color = Color(0xFF2196F3)),
lineHorizontalAlignment = BOTTOM,
),
) {
// Code to add events
}Use the JetLimeEventDefaults.eventStyle()
JetLimeEvent(
style = JetLimeEventDefaults.eventStyle(
position = position,
pointColor = Color(0xFF2889D6),
pointFillColor = Color(0xFFD5F2FF),
pointRadius = 14.dp,
pointAnimation = JetLimeEventDefaults.pointAnimation(),
pointType = EventPointType.filled(0.8f),
pointStrokeWidth = 2.dp,
pointStrokeColor = MaterialTheme.colorScheme.onBackground,
),
) {
// Code to add event content
}The timeline line and point circles can be set to either side.
For a JetLimeColumn the alignment can be set to LEFT or RIGHT
lineVerticalAlignment = LEFT or RIGHT // Default is LEFTFor a JetLimeRow the alignment can be set to TOP or BOTTOM
lineHorizontalAlignment = TOP or BOTTOM // Default is TOPThe line can be drawn by passing a Brush object to lineBrush in a columnStyle or rowStyle.
Default values can also be used from JetLimeDefaults and colors can be modified for quick setup:
lineBrush = JetLimeDefaults.lineGradientBrush()
or
lineBrush = JetLimeDefaults.solidBrush()A dashed/dotted line can also be drawn using the pathEffect property by passing a PathEffect to a columnStyle or rowStyle.
style = JetLimeDefaults.columnStyle(
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(30f, 30f),
phase = 0f,
)
)The contentDistance in Dp specifies how far the timeline line should be from the timeline content.
The itemSpacing in Dp specifies the gap between the event items.
The lineThickness in Dp the thickness of the timeline line.
We always need to pass the position to the eventStyle that will be received in the JetLimeColumn lambda.
This is needed so that JetLimeColumn can calculate the position of an event in the list at any time.
Based on the calculation it will assign either of the three EventPosition: START, MIDDLE or END.
This classification is needed to render correct lines for start and end items.
JetLimeColumn(
itemsList = ItemsList(items),
key = { _, item -> item.id },
) { index, item, position ->
JetLimeEvent(
style = JetLimeEventDefaults.eventStyle(
position = position
),
) {
// Content here
}
}The pointType of type EventPointType specifies the style of the point circle.
It can be any of the three types: EMPTY, FILLED or CUSTOM.
For using EMPTY
pointType = EventPointType.EMPTYFor using FILLED, the filled() function has to be used which takes an optional fillPercent
pointType = EventPointType.filled(0.8f)For using CUSTOM, the custom() function has to be used which takes an icon of Painter.
This can be used to use a custom icon instead of the default types defined. An optional tint can also be applied on the icon.
pointType = EventPointType.custom(icon = painterResource(id = R.drawable.icon_check), tint = Color.Green)The pointAnimation of type EventPointAnimation specifies the animation of the point circle.
To enable the default animation
pointAnimation = JetLimeEventDefaults.pointAnimation()To use a custom animation initialValue, targetValue and animationSpec can be passed to pointAnimation().
animationSpec should be of the type InfiniteRepeatableSpec<Float>.
The pointColor is the color of the event point circle background.
The pointFillColor is the fill color of the event point circle which is drawn over the pointColor.
The pointRadius in Dp is the radius of the point circle.
The pointStrokeWidth in Dp is the width of the circle border.
The pointStrokeColor is the color of the circle border.
The full API documentation is available here: JetLime Documentation
- Timeline-View by Vipul Asri
- This amazing blog by Vita Sokolova on Timeline component with Jetpack Compose
Would love to receive contributions! Read contribution guidelines for more information regarding contribution.
Have any questions, doubts or want to present your opinions, views? You're always welcome. You can start discussions.
MIT License
Copyright (c) 2024 Pushpal Roy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.








