Document NumberPicker Composable and it's util classes, functions

This commit is contained in:
Gergely Hegedus 2022-06-15 13:08:59 +03:00
parent ef15aca31f
commit db9c62884f
9 changed files with 151 additions and 29 deletions

View file

@ -31,7 +31,7 @@ fun NumberPickerScreen() {
var selected by remember { mutableStateOf(0) }
NumberPicker(
modifier = Modifier.defaultMinSize(minWidth = 200.dp),
onSelectedChange = {
onSelectedValueChange = {
selected = it
},
textStyle = MaterialTheme.typography.h5,
@ -44,7 +44,7 @@ fun NumberPickerScreen() {
NumberPicker(
config = NumberPickerConfig.configMinutePicker,
selectedValue = selected,
onSelectedChange = { selected = it },
onSelectedValueChange = { selected = it },
roundAround = false,
textStyle = MaterialTheme.typography.h5
)
@ -55,7 +55,7 @@ fun NumberPickerScreen() {
NumberPicker(
config = NumberPickerConfig.configMinutePicker,
selectedValue = selected,
onSelectedChange = { selected = it },
onSelectedValueChange = { selected = it },
timePicker = { LinedInnerTextPicker(modifier = Modifier.defaultMinSize(minWidth = 200.dp)) }
)
}
@ -66,7 +66,7 @@ fun NumberPickerScreen() {
NumberPicker(
config = NumberPickerConfig.configHourPicker24,
selectedValue = selected,
onSelectedChange = { selected = it }
onSelectedValueChange = { selected = it }
) {
TextPicker(
modifier = Modifier.defaultMinSize(minWidth = 200.dp),
@ -88,7 +88,7 @@ fun NumberPickerScreen() {
NumberPicker(
config = NumberPickerConfig(maximum = 5, minimum = 1, skipInBetween = 1),
selectedValue = selected,
onSelectedChange = { selected = it }
onSelectedValueChange = { selected = it }
)
}
}
@ -99,7 +99,7 @@ fun NumberPickerScreen() {
NumberPicker(
config = NumberPickerConfig(maximum = 5, minimum = 1, skipInBetween = 2),
selectedValue = selected,
onSelectedChange = { selected = it }
onSelectedValueChange = { selected = it }
)
}
}
@ -110,7 +110,7 @@ fun NumberPickerScreen() {
NumberPicker(
config = NumberPickerConfig(maximum = 5, minimum = 1, skipInBetween = 1, reversedOrder = true),
selectedValue = selected,
onSelectedChange = { selected = it }
onSelectedValueChange = { selected = it }
)
}
}
@ -122,7 +122,7 @@ fun NumberPickerScreen() {
config = NumberPickerConfig(maximum = 5, minimum = 1, skipInBetween = 2, reversedOrder = true),
selectedValue = selected,
roundAround = false,
onSelectedChange = { selected = it },
onSelectedValueChange = { selected = it },
)
}
}

View file

@ -7,12 +7,29 @@ import androidx.compose.ui.text.TextStyle
import org.fknives.android.compose.picker.text.TextPickerState
import org.fknives.android.compose.picker.text.util.TextPickerDefaults
/**
* Configuration API around [TextPicker][org.fknives.android.compose.picker.text.TextPicker].
*
* Sets up inner StateManagement of [TextPicker][org.fknives.android.compose.picker.text.TextPicker] in a [NumberPickerScope]
* then places it via [CustomInnerTextPicker].
*
* @param modifier [Modifier] of [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
* @param config Configuration of NumberPicker. Defines the Number Range that should be shown.
* @param selectedValue The selected value, expected to be between [config]'s minimum and maximum.
* @param onSelectedValueChange Notified when the Selected Value Changes.
* @param onIndexDifferenceChanging Signals the animation changes, how much the current dragging is away from index of [selectedValue].
* Negative values mean the index were decreased, Positive means it was increased.
* **IMPORTANT! works with index-difference, not values (minimumValue = 0 index)**
* @param textStyle TextStyle of [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
* @param roundAround roundAround of [TextPicker][org.fknives.android.compose.picker.text.TextPicker].
* Should behave like a Wheel, or should be limited.
*/
@Composable
fun NumberPicker(
modifier: Modifier = Modifier,
config: NumberPickerConfig,
selectedValue: Int,
onSelectedChange: (Int) -> Unit,
onSelectedValueChange: (Int) -> Unit,
onIndexDifferenceChanging: (Int) -> Unit = TextPickerDefaults.onIndexDifferenceChanging,
textStyle: TextStyle = LocalTextStyle.current,
roundAround: Boolean = TextPickerDefaults.roundAround,
@ -20,7 +37,7 @@ fun NumberPicker(
NumberPicker(
config = config,
selectedValue = selectedValue,
onSelectedChange = onSelectedChange,
onSelectedValueChange = onSelectedValueChange,
onIndexDifferenceChanging = onIndexDifferenceChanging
) {
CustomInnerTextPicker(
@ -31,11 +48,28 @@ fun NumberPicker(
}
}
/**
* Configuration API around [TextPicker][org.fknives.android.compose.picker.text.TextPicker].
*
* Sets up inner StateManagement of [TextPicker][org.fknives.android.compose.picker.text.TextPicker] in a [NumberPickerScope]
* then places it via [timePicker].
*
* @param config Configuration of NumberPicker. Defines the Number Range that should be shown.
* @param selectedValue The selected value, expected to be between [config]'s minimum and maximum.
* @param onSelectedValueChange Notified when the Selected Value Changes.
* @param onIndexDifferenceChanging Signals the animation changes, how much the current dragging is away from index of [selectedValue].
* Negative values mean the index were decreased, Positive means it was increased.
* **IMPORTANT! works with index-difference, not values (minimumValue = 0 index)**
* Should behave like a Wheel, or should be limited.
* @param state TextPickerState of [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
* @param timePicker The Lambda placing the TimePicker. [NumberPickerScope] is provided with the configuration setup.
* *Note: Check [StandardInnerTextPicker], [CustomInnerTextPicker], if you wish to customize.*
*/
@Composable
fun NumberPicker(
config: NumberPickerConfig,
selectedValue: Int,
onSelectedChange: (Int) -> Unit,
onSelectedValueChange: (Int) -> Unit,
onIndexDifferenceChanging: (Int) -> Unit = TextPickerDefaults.onIndexDifferenceChanging,
state: TextPickerState = rememberNumberPickerState(selectedValue = selectedValue, config = config),
timePicker: @Composable NumberPickerScope.() -> Unit = { StandardInnerTextPicker() }
@ -46,7 +80,7 @@ fun NumberPicker(
state = state,
config = config,
onIndexDifferenceChanging = onIndexDifferenceChanging,
onSelectedChange = onSelectedChange
onSelectedValueChange = onSelectedValueChange
)
timePicker(numberPickerScope)

View file

@ -2,6 +2,38 @@ package org.fknives.android.compose.picker.number
import androidx.compose.runtime.Immutable
/**
* Configuration of [NumberPicker]
*
* [minimum] The minimum value shown inside the [NumberPicker]. Minimum Value included in the List of Elements.
* [maximum] The maximum value shown inside the [NumberPicker]. Maximum Value included in the List of Elements.
* [reversedOrder] false, means goes from [minimum]..[maximum], true means [maximum]..[minimum]
* [skipInBetween], number of elements skipped when going from one value to another.
*
* Example1:
* minimum = 1, maximum = 3, reversedOrder = false, skipInBetween=0
* =>
* [1,2,3]
* *Note: No skipping, no reverse, so all elements from 1 to 3*
*
* Example2:
* minimum = 1, maximum = 3, reversedOrder = true, skipInBetween=0
* =>
* [3,2,1]
* *Note: No skipping, reverse, so all elements from 3 to 1*
*
* Example3:
* minimum = 1, maximum = 5, reversedOrder = false, skipInBetween=1
* =>
* [1,3,5]
* *Note: Skipping 1 element, no reverse, so starting from 1. Then skipping 2, so 3. Then skipping 4 so 5.*
*
* Example4:
* minimum = 1, maximum = 5, reversedOrder = true, skipInBetween=2
* =>
* [5,2]
* *Note: Skipping 2 element, Reverse, so starting from 5. Then skipping 4 and 3, so 2. Next would be smaller than minimal so, that's it.*
*/
@Immutable
data class NumberPickerConfig(
val maximum: Int,

View file

@ -6,6 +6,36 @@ import androidx.compose.runtime.remember
import org.fknives.android.compose.picker.text.util.TextPickerDefaults
import org.fknives.android.compose.picker.text.TextPickerState
/**
* Prepared parameters for [TextPicker][org.fknives.android.compose.picker.text.TextPicker].
*
* [state] The [TextPickerState] expected to be set to [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
*
* [onIndexDifferenceChanging] The onIndexDifferenceChanging Listener expected to be set to
* [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
*
* [onSelectedIndexChange] The onSelectedIndexChange Listener expected to be set to
* [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
*
* [textForIndex] The IndexToNumberVlaue Converter expected to be set to [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
*
* [selectedIndex] The selectedIndex expected to be set to [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
*
* [itemCount] The selectedIndex expected to be set to [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
*/
@Immutable
interface NumberPickerScope {
val state: TextPickerState
val onIndexDifferenceChanging: (Int) -> Unit
val onSelectedIndexChange: (Int) -> Unit
val textForIndex: (Int) -> String
val selectedIndex: Int get() = state.selected
val itemCount: Int get() = state.itemCount
}
/**
* Data class implementation of [NumberPickerScope]
*/
@Immutable
data class NumberPickerScopeImpl(
override val state: TextPickerState,
@ -17,11 +47,20 @@ data class NumberPickerScopeImpl(
override val itemCount: Int get() = state.itemCount
}
/**
* Caching function, preparing the [NumberPickerScope] from simple parameters.
*
* @param state The [TextPickerState] expected to be set to [TextPicker][org.fknives.android.compose.picker.text.TextPicker]
* @param config The NumberPickers config. Used to convert between TextPicker's Index and NumberPicker's values.
* @param onSelectedValueChange NumberPicker's onSelectedValueChange Listener
* @param onIndexDifferenceChanging NumberPicker's onIndexDifferenceChanging Listener
* @param keys any additional keys, to signal changing of the scope cache.
*/
@Composable
fun rememberNumberPickerScope(
state: TextPickerState,
config: NumberPickerConfig,
onSelectedChange: (Int) -> Unit,
onSelectedValueChange: (Int) -> Unit,
onIndexDifferenceChanging: (Int) -> Unit = TextPickerDefaults.onIndexDifferenceChanging,
vararg keys: Any?
): NumberPickerScope {
@ -34,18 +73,8 @@ fun rememberNumberPickerScope(
textForIndex = { "${indexToNumber(it)}" },
onIndexDifferenceChanging = onIndexDifferenceChanging,
onSelectedIndexChange = {
onSelectedChange(indexToNumber(it))
onSelectedValueChange(indexToNumber(it))
}
)
}
}
@Immutable
interface NumberPickerScope {
val state: TextPickerState
val onIndexDifferenceChanging: (Int) -> Unit
val onSelectedIndexChange: (Int) -> Unit
val textForIndex: (Int) -> String
val selectedIndex: Int get() = state.selected
val itemCount: Int get() = state.itemCount
}

View file

@ -8,6 +8,12 @@ import org.fknives.android.compose.picker.text.LinedTextPicker
import org.fknives.android.compose.picker.text.TextPicker
import org.fknives.android.compose.picker.text.util.TextPickerDefaults
/**
* Custom [TextPicker] Creator for [NumberPicker], containing all styling [TextPicker].
* Keeps all the default values of [TextPicker].
*
* For More Customization, Give your Custom TextPicker callback to [NumberPicker]
*/
@Composable
fun NumberPickerScope.CustomInnerTextPicker(
modifier: Modifier = Modifier,
@ -27,6 +33,10 @@ fun NumberPickerScope.CustomInnerTextPicker(
)
}
/**
* Default [TextPicker] Creator for [NumberPicker].
* Keeps all the default values of [TextPicker].
*/
@Composable
fun NumberPickerScope.StandardInnerTextPicker(modifier: Modifier = Modifier) {
TextPicker(
@ -40,6 +50,10 @@ fun NumberPickerScope.StandardInnerTextPicker(modifier: Modifier = Modifier) {
)
}
/**
* Default [LinedTextPicker] Creator for [NumberPicker].
* Keeps all the default values of [LinedTextPicker].
*/
@Composable
fun NumberPickerScope.LinedInnerTextPicker(modifier: Modifier = Modifier) {
LinedTextPicker(

View file

@ -5,7 +5,11 @@ import androidx.compose.runtime.remember
import org.fknives.android.compose.picker.text.TextPickerState
import org.fknives.android.compose.picker.text.util.rememberTextPickerState
/**
* Caches function converting from TextPicker's Index to NumberPicker's NumberValues, defined by [config]
*
* Inverse of [valueToIndex]
*/
@Composable
fun rememberNumberPickerIndexToNumber(config: NumberPickerConfig): (Int) -> Int =
remember(config) {
@ -20,6 +24,11 @@ fun rememberNumberPickerIndexToNumber(config: NumberPickerConfig): (Int) -> Int
}
}
/**
* Function converting from NumberPicker's NumberValues to TextPicker's Index, defined by [config].
*
* Inverse of [valueToIndex]
*/
private fun valueToIndex(config: NumberPickerConfig, value: Int): Int =
if (config.reversedOrder) {
(config.maximum - value) / (config.skipInBetween + 1)
@ -27,6 +36,9 @@ private fun valueToIndex(config: NumberPickerConfig, value: Int): Int =
(value - config.minimum) / (config.skipInBetween + 1)
}
/**
* Caches [TextPickerState] created from the NumberPicker's [config] and [selectedValue].
*/
@Composable
fun rememberNumberPickerState(selectedValue: Int, config: NumberPickerConfig): TextPickerState {
val selected = valueToIndex(value = selectedValue, config = config)

View file

@ -44,6 +44,7 @@ import org.fknives.android.compose.picker.text.util.rememberSafeTextForIndex
* Setting this to False, means the first element has no elements above it, and the last element has no element below it.
* @param onIndexDifferenceChanging Signals the animation changes, how much the current dragging is away from [selectedIndex].
* Negative values mean the index were decreased, Positive means it was increased.
* **IMPORTANT! works with index-difference, not index**
* @param state Animation State for the TextPicker
* @param animator Uses state to Animate the Composable elements. Handles continous drag, calculating fling and snapping to an index.
* @param textPickerContent The actual Composables inside the TextPicker, by default it is the 4 Texts

View file

@ -21,7 +21,7 @@ fun TimePicker(
val hourScope = rememberNumberPickerScope(
state = hourState,
config = hourConfig,
onSelectedChange = {
onSelectedValueChange = {
onSelectedTimeChanged(selectedTime.copy(hour = it))
}
)
@ -31,7 +31,7 @@ fun TimePicker(
val minuteScope = rememberNumberPickerScope(
state = minuteState,
config = minuteConfig,
onSelectedChange = {
onSelectedValueChange = {
onSelectedTimeChanged(selectedTime.copy(minute = it))
}
)

View file

@ -43,7 +43,7 @@ fun ClockTimePicker(
changingIsAM = isAMResultByHourLapsCounter(lapsCounter, selectedTime.isAM)
}
},
onSelectedChange = {
onSelectedValueChange = {
onSelectedTimeChanged(selectedTime.copy(hour = it, isAM = changingIsAM))
},
keys = arrayOf(changingHour, hoursLapCounterByIndex, changingIsAM)
@ -66,7 +66,7 @@ fun ClockTimePicker(
changingIsAM = isAMResultByHourLapsCounter(lapsCounter, selectedTime.isAM)
changingHour = hourDifference
},
onSelectedChange = {
onSelectedValueChange = {
onSelectedTimeChanged(selectedTime.copy(hour = selectedTime.hour + changingHour, minute = it, isAM = changingIsAM))
},
keys = arrayOf(changingHour, hoursLapCounterByIndex, changingIsAM)