Skip to content

Commit af26b80

Browse files
committed
feat(Slider): Add SliderState and basic computation
1 parent c3c53cf commit af26b80

File tree

13 files changed

+256
-52
lines changed

13 files changed

+256
-52
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*.iml
22
.gradle
33
/local.properties
4+
/.idea/
45
/.idea/caches
56
/.idea/libraries
67
/.idea/modules.xml

.idea/deploymentTargetDropDown.xml

Lines changed: 30 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/src/main/java/io/monstarlab/mosaic/MainActivity.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import android.os.Bundle
44
import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
66
import androidx.activity.enableEdgeToEdge
7+
import androidx.compose.material3.Slider
78
import androidx.compose.material3.Text
89
import androidx.compose.runtime.Composable
910
import androidx.compose.ui.Modifier
1011
import androidx.compose.ui.tooling.preview.Preview
1112
import io.monstarlab.mosaic.features.SliderDemo
1213
import io.monstarlab.mosaic.ui.theme.MosaicTheme
14+
import kotlinx.coroutines.delay
15+
import kotlin.time.Duration
16+
import kotlin.time.Duration.Companion.seconds
1317

1418
class MainActivity : ComponentActivity() {
1519
override fun onCreate(savedInstanceState: Bundle?) {

demo/src/main/java/io/monstarlab/mosaic/features/SliderDemo.kt

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,61 @@
11
package io.monstarlab.mosaic.features
22

3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Box
35
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Spacer
47
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.layout.size
59
import androidx.compose.foundation.shape.RoundedCornerShape
610
import androidx.compose.material3.Scaffold
11+
import androidx.compose.material3.Text
712
import androidx.compose.runtime.Composable
13+
import androidx.compose.runtime.getValue
14+
import androidx.compose.runtime.mutableFloatStateOf
15+
import androidx.compose.runtime.mutableStateOf
16+
import androidx.compose.runtime.remember
17+
import androidx.compose.runtime.setValue
818
import androidx.compose.ui.Modifier
919
import androidx.compose.ui.draw.clip
1020
import androidx.compose.ui.graphics.Color
1121
import androidx.compose.ui.tooling.preview.Preview
1222
import androidx.compose.ui.unit.dp
1323
import io.monstarlab.mosaic.slider.Slider
1424
import io.monstarlab.mosaic.slider.SliderColors
15-
25+
import androidx.compose.material3.Slider as MaterialSlider
1626
@Composable
1727
fun SliderDemo() = Scaffold(modifier = Modifier) {
18-
Column(modifier = Modifier.padding(it).padding(16.dp)) {
28+
29+
var materialSliderValue by remember { mutableFloatStateOf(50f) }
30+
var mosaicSliderValue by remember { mutableFloatStateOf(50f) }
31+
32+
33+
Column(modifier = Modifier
34+
.padding(it)
35+
.padding(16.dp)
36+
.background(Color.LightGray)) {
37+
38+
MaterialSlider(
39+
value = materialSliderValue,
40+
onValueChange = { materialSliderValue = it},
41+
valueRange = 0f..100f
42+
)
43+
Text(text = materialSliderValue.toString())
44+
45+
Spacer(modifier = Modifier.size(32.dp))
46+
1947
Slider(
20-
value = 0.5f,
21-
onValueChange = {},
48+
value = mosaicSliderValue,
49+
onValueChange = { mosaicSliderValue = it },
2250
colors = SliderColors(Color.Red),
2351
modifier = Modifier.clip(RoundedCornerShape(2.dp)),
24-
)
52+
range = 0f..100f
53+
) {
54+
Box(modifier = Modifier.background(Color.Yellow).size(32.dp))
55+
}
56+
Text(text = mosaicSliderValue.toString())
57+
58+
2559
}
2660
}
2761

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.monstarlab.mosaic.slider
2+
3+
import androidx.compose.ui.util.lerp
4+
5+
internal fun scale(a1: Float, b1: Float, x1: Float, a2: Float, b2: Float) =
6+
lerp(a2, b2, calcFraction(a1, b1, x1))
7+
8+
internal fun calcFraction(a: Float, b: Float, pos: Float) =
9+
(if (b - a == 0f) 0f else (pos - a) / (b - a)).coerceIn(0f, 1f)
Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,58 @@
11
package io.monstarlab.mosaic.slider
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.gestures.Orientation
5+
import androidx.compose.foundation.gestures.draggable
6+
import androidx.compose.foundation.interaction.MutableInteractionSource
57
import androidx.compose.foundation.layout.Box
6-
import androidx.compose.foundation.layout.BoxScope
7-
import androidx.compose.foundation.layout.BoxWithConstraints
8-
import androidx.compose.foundation.layout.Column
9-
import androidx.compose.foundation.layout.fillMaxSize
10-
import androidx.compose.foundation.layout.fillMaxWidth
118
import androidx.compose.foundation.layout.size
129
import androidx.compose.foundation.shape.CircleShape
1310
import androidx.compose.runtime.Composable
14-
import androidx.compose.ui.Alignment
11+
import androidx.compose.runtime.LaunchedEffect
12+
import androidx.compose.runtime.remember
1513
import androidx.compose.ui.Modifier
1614
import androidx.compose.ui.graphics.Color
17-
import androidx.compose.ui.layout.Layout
15+
import androidx.compose.ui.platform.LocalLayoutDirection
1816
import androidx.compose.ui.tooling.preview.Preview
17+
import androidx.compose.ui.unit.LayoutDirection
1918

2019
@Composable
2120
public fun Slider(
2221
value: Float,
2322
onValueChange: (Float) -> Unit,
2423
colors: SliderColors,
2524
modifier: Modifier = Modifier,
26-
thumb: @Composable () -> Unit = { DefaultSliderThumb(colors = colors) }
25+
range: ClosedFloatingPointRange<Float> = 0f..1f,
26+
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
27+
thumb: @Composable () -> Unit = { DefaultSliderThumb(colors = colors) },
2728
) {
29+
val state = rememberSliderState()
30+
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
31+
32+
state.value = value
33+
state.range = range
34+
state.onValueChange = onValueChange
35+
36+
val draggable = modifier.draggable(
37+
state = state,
38+
orientation = Orientation.Horizontal,
39+
enabled = true,
40+
interactionSource = interactionSource,
41+
startDragImmediately = true,
42+
reverseDirection = isRtl,
43+
)
2844

2945
SliderLayout(
30-
progress = value,
46+
modifier = modifier.then(draggable),
3147
thumb = thumb,
3248
track = {
3349
SliderTrack(
34-
modifier = modifier,
35-
progress = value,
50+
progress = state.valueAsFraction,
3651
colors = colors,
3752
)
38-
}
53+
},
54+
onDimensionsResolved = state::updateDimensions,
55+
value = state.valueAsFraction
3956
)
4057
}
4158

@@ -46,8 +63,8 @@ internal fun DefaultSliderThumb(colors: SliderColors) {
4663
.size(SliderDefaults.ThumbSize)
4764
.background(
4865
color = colors.active,
49-
shape = CircleShape
50-
)
66+
shape = CircleShape,
67+
),
5168
)
5269
}
5370

@@ -57,6 +74,6 @@ private fun PreviewSlider() {
5774
Slider(
5875
value = 0.5f,
5976
onValueChange = {},
60-
colors = SliderColors(Color.Yellow)
77+
colors = SliderColors(Color.Yellow),
6178
)
62-
}
79+
}

slider/src/main/java/io/monstarlab/mosaic/slider/SliderColors.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ public data class SliderColors(
66
val active: Color,
77
val disabled: Color = active.copy(alpha = 0.2f),
88
val inactive: Color = active.copy(alpha = 0.5f),
9-
)
9+
)

slider/src/main/java/io/monstarlab/mosaic/slider/SliderDefaults.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ internal object SliderDefaults {
66
val TrackHeight = 4.dp
77
val ThumbSize = 16.dp
88
val HandleHeight = 16.0.dp
9-
val HandleWidth = 20.0.dp
9+
val HandleWidth = 16.0.dp
1010
}

slider/src/main/java/io/monstarlab/mosaic/slider/SliderLayout.kt

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import kotlin.math.roundToInt
2020

2121
@Composable
2222
public fun SliderLayout(
23-
progress: Float,
23+
value: Float,
24+
onDimensionsResolved: (Float, Float) -> Unit,
2425
modifier: Modifier = Modifier,
2526
track: @Composable () -> Unit,
2627
thumb: @Composable () -> Unit,
@@ -50,15 +51,26 @@ public fun SliderLayout(
5051
)
5152

5253
val sliderHeight = max(thumbPlaceable.height, trackPlaceable.height)
53-
val sliderWidth = trackPlaceable.width
54+
val sliderWidth = trackPlaceable.width + thumbPlaceable.width
55+
onDimensionsResolved(sliderWidth.toFloat(), thumbPlaceable.width.toFloat())
56+
57+
val trackOffsetX = thumbPlaceable.width / 2
58+
val thumbOffsetX = ((trackPlaceable.width) * value).roundToInt()
59+
val trackOffsetY = (sliderHeight - trackPlaceable.height) / 2
60+
val thumbOffsetY = (sliderHeight - thumbPlaceable.height) / 2
61+
5462
layout(sliderWidth, sliderHeight) {
55-
val thumbX = (trackPlaceable.width * progress).roundToInt() - thumbPlaceable.width / 2
56-
val trackY = sliderHeight - trackPlaceable.height
57-
trackPlaceable.placeRelative(0, trackY / 2)
58-
thumbPlaceable.place(thumbX, 0)
59-
}
63+
trackPlaceable.placeRelative(
64+
trackOffsetX,
65+
trackOffsetY
66+
)
67+
thumbPlaceable.placeRelative(
68+
thumbOffsetX,
69+
thumbOffsetY
70+
)
6071
}
6172
}
73+
}
6274

6375
internal enum class SliderLayoutElements {
6476
Track,
@@ -68,23 +80,26 @@ internal enum class SliderLayoutElements {
6880
@Preview
6981
@Composable
7082
private fun PreviewSliderLayout() {
71-
SliderLayout(
72-
modifier = Modifier.fillMaxWidth(1f),
73-
progress = 0.5f,
74-
track = {
75-
Box(
76-
modifier = Modifier
77-
.background(Color.Yellow)
78-
.height(15.dp)
79-
.fillMaxWidth(),
80-
)
81-
},
82-
thumb = {
83-
Box(
84-
modifier = Modifier
85-
.size(32.dp)
86-
.background(Color.Black, shape = CircleShape),
87-
)
88-
},
89-
)
83+
Box(modifier = Modifier.background(Color.Red)) {
84+
SliderLayout(
85+
onDimensionsResolved = { _, _ -> },
86+
modifier = Modifier.fillMaxWidth(0.5f),
87+
value = 1f,
88+
track = {
89+
Box(
90+
modifier = Modifier
91+
.background(Color.Yellow)
92+
.height(12.dp)
93+
.fillMaxWidth(),
94+
)
95+
},
96+
thumb = {
97+
Box(
98+
modifier = Modifier
99+
.size(32.dp)
100+
.background(Color.Black, shape = CircleShape),
101+
)
102+
},
103+
)
104+
}
90105
}

0 commit comments

Comments
 (0)