multiplatform: FWheelPicker dependency from source (#2659)
* multiplatform: FWheelPicker dependency from source * EOLs --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
313d3a732d
commit
7fea9c85bd
@@ -96,10 +96,6 @@ kotlin {
|
||||
api("androidx.camera:camera-lifecycle:${camerax_version}")
|
||||
api("androidx.camera:camera-view:${camerax_version}")
|
||||
|
||||
// LALAL REPLACE IT WITH SOURCE
|
||||
// Wheel picker
|
||||
api("com.github.zj565061763:compose-wheel-picker:1.0.0-alpha10")
|
||||
|
||||
// LALAL REMOVE
|
||||
api("org.jsoup:jsoup:1.13.1")
|
||||
api("com.godaddy.android.colorpicker:compose-color-picker-jvm:0.7.0")
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
package com.sd.lib.compose.wheel_picker
|
||||
|
||||
import androidx.compose.animation.core.DecayAnimationSpec
|
||||
import androidx.compose.animation.core.calculateTargetValue
|
||||
import androidx.compose.animation.core.exponentialDecay
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.Velocity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
interface FWheelPickerContentScope {
|
||||
val state: FWheelPickerState
|
||||
}
|
||||
|
||||
interface FWheelPickerContentWrapperScope {
|
||||
val state: FWheelPickerState
|
||||
|
||||
@Composable
|
||||
fun content(index: Int)
|
||||
}
|
||||
|
||||
// LALAL: make separate repo for this
|
||||
|
||||
@Composable
|
||||
fun FVerticalWheelPicker(
|
||||
count: Int,
|
||||
state: FWheelPickerState = rememberFWheelPickerState(),
|
||||
modifier: Modifier = Modifier,
|
||||
key: ((index: Int) -> Any)? = null,
|
||||
itemHeight: Dp = 35.dp,
|
||||
unfocusedCount: Int = 1,
|
||||
userScrollEnabled: Boolean = true,
|
||||
reverseLayout: Boolean = false,
|
||||
debug: Boolean = false,
|
||||
focus: @Composable () -> Unit = { FWheelPickerFocusVertical() },
|
||||
contentWrapper: @Composable FWheelPickerContentWrapperScope.(index: Int) -> Unit = DefaultWheelPickerContentWrapper,
|
||||
content: @Composable FWheelPickerContentScope.(index: Int) -> Unit,
|
||||
) {
|
||||
WheelPicker(
|
||||
isVertical = true,
|
||||
count = count,
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
key = key,
|
||||
itemSize = itemHeight,
|
||||
unfocusedCount = unfocusedCount,
|
||||
userScrollEnabled = userScrollEnabled,
|
||||
reverseLayout = reverseLayout,
|
||||
debug = debug,
|
||||
focus = focus,
|
||||
contentWrapper = contentWrapper,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FHorizontalWheelPicker(
|
||||
count: Int,
|
||||
state: FWheelPickerState = rememberFWheelPickerState(),
|
||||
modifier: Modifier = Modifier,
|
||||
key: ((index: Int) -> Any)? = null,
|
||||
itemWidth: Dp = 35.dp,
|
||||
unfocusedCount: Int = 1,
|
||||
userScrollEnabled: Boolean = true,
|
||||
reverseLayout: Boolean = false,
|
||||
debug: Boolean = false,
|
||||
focus: @Composable () -> Unit = { FWheelPickerFocusHorizontal() },
|
||||
contentWrapper: @Composable FWheelPickerContentWrapperScope.(index: Int) -> Unit = DefaultWheelPickerContentWrapper,
|
||||
content: @Composable FWheelPickerContentScope.(index: Int) -> Unit,
|
||||
) {
|
||||
WheelPicker(
|
||||
isVertical = false,
|
||||
count = count,
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
key = key,
|
||||
itemSize = itemWidth,
|
||||
unfocusedCount = unfocusedCount,
|
||||
userScrollEnabled = userScrollEnabled,
|
||||
reverseLayout = reverseLayout,
|
||||
debug = debug,
|
||||
focus = focus,
|
||||
contentWrapper = contentWrapper,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WheelPicker(
|
||||
isVertical: Boolean,
|
||||
count: Int,
|
||||
state: FWheelPickerState,
|
||||
modifier: Modifier,
|
||||
key: ((index: Int) -> Any)?,
|
||||
itemSize: Dp,
|
||||
unfocusedCount: Int,
|
||||
userScrollEnabled: Boolean,
|
||||
reverseLayout: Boolean,
|
||||
debug: Boolean,
|
||||
focus: @Composable () -> Unit,
|
||||
contentWrapper: @Composable FWheelPickerContentWrapperScope.(index: Int) -> Unit,
|
||||
content: @Composable FWheelPickerContentScope.(index: Int) -> Unit,
|
||||
) {
|
||||
require(count >= 0) { "require count >= 0" }
|
||||
require(unfocusedCount >= 1) { "require unfocusedCount >= 1" }
|
||||
|
||||
state.debug = debug
|
||||
LaunchedEffect(state, count) {
|
||||
state.notifyCountChanged(count)
|
||||
}
|
||||
|
||||
val nestedScrollConnection = remember(state) {
|
||||
WheelPickerNestedScrollConnection(state)
|
||||
}.apply {
|
||||
this.isVertical = isVertical
|
||||
this.itemSizePx = with(LocalDensity.current) { itemSize.roundToPx() }
|
||||
this.reverseLayout = reverseLayout
|
||||
}
|
||||
|
||||
val totalSize = remember(itemSize, unfocusedCount) {
|
||||
itemSize * (unfocusedCount * 2 + 1)
|
||||
}
|
||||
|
||||
val contentWrapperScope = remember(state) {
|
||||
val contentScope = WheelPickerContentScopeImpl(state)
|
||||
FWheelPickerContentWrapperScopeImpl(contentScope)
|
||||
}.apply {
|
||||
this.content = content
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.nestedScroll(nestedScrollConnection)
|
||||
.run {
|
||||
if (totalSize > 0.dp) {
|
||||
if (isVertical) {
|
||||
height(totalSize).widthIn(40.dp)
|
||||
} else {
|
||||
width(totalSize).heightIn(40.dp)
|
||||
}
|
||||
} else {
|
||||
this
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
|
||||
val lazyListScope: LazyListScope.() -> Unit = {
|
||||
repeat(unfocusedCount) {
|
||||
item {
|
||||
ItemSizeBox(
|
||||
isVertical = isVertical,
|
||||
itemSize = itemSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
items(
|
||||
count = count,
|
||||
key = key,
|
||||
) { index ->
|
||||
ItemSizeBox(
|
||||
isVertical = isVertical,
|
||||
itemSize = itemSize,
|
||||
) {
|
||||
contentWrapperScope.contentWrapper(index)
|
||||
}
|
||||
}
|
||||
|
||||
repeat(unfocusedCount) {
|
||||
item {
|
||||
ItemSizeBox(
|
||||
isVertical = isVertical,
|
||||
itemSize = itemSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isVertical) {
|
||||
LazyColumn(
|
||||
state = state.lazyListState,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
reverseLayout = reverseLayout,
|
||||
userScrollEnabled = userScrollEnabled,
|
||||
modifier = Modifier.matchParentSize(),
|
||||
content = lazyListScope,
|
||||
)
|
||||
} else {
|
||||
LazyRow(
|
||||
state = state.lazyListState,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
reverseLayout = reverseLayout,
|
||||
userScrollEnabled = userScrollEnabled,
|
||||
modifier = Modifier.matchParentSize(),
|
||||
content = lazyListScope,
|
||||
)
|
||||
}
|
||||
|
||||
ItemSizeBox(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
isVertical = isVertical,
|
||||
itemSize = itemSize,
|
||||
) {
|
||||
focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ItemSizeBox(
|
||||
modifier: Modifier = Modifier,
|
||||
isVertical: Boolean,
|
||||
itemSize: Dp,
|
||||
content: @Composable () -> Unit = { },
|
||||
) {
|
||||
Box(
|
||||
modifier
|
||||
.run {
|
||||
if (isVertical) {
|
||||
height(itemSize)
|
||||
} else {
|
||||
width(itemSize)
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
private class WheelPickerNestedScrollConnection(
|
||||
private val state: FWheelPickerState,
|
||||
) : NestedScrollConnection {
|
||||
var isVertical: Boolean? = null
|
||||
var itemSizePx: Int? = null
|
||||
var reverseLayout: Boolean? = null
|
||||
|
||||
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
|
||||
state.synchronizeCurrentIndexSnapshot()
|
||||
return super.onPostScroll(consumed, available, source)
|
||||
}
|
||||
|
||||
override suspend fun onPreFling(available: Velocity): Velocity {
|
||||
val currentIndex = state.synchronizeCurrentIndexSnapshot()
|
||||
return if (currentIndex >= 0) {
|
||||
val flingItemCount = available.flingItemCount(
|
||||
isVertical = isVertical!!,
|
||||
itemSize = itemSizePx!!,
|
||||
decay = exponentialDecay(2f),
|
||||
reverseLayout = reverseLayout!!,
|
||||
)
|
||||
|
||||
if (flingItemCount.absoluteValue > 0) {
|
||||
state.animateScrollToIndex(currentIndex - flingItemCount)
|
||||
} else {
|
||||
state.animateScrollToIndex(currentIndex)
|
||||
}
|
||||
available
|
||||
} else {
|
||||
super.onPreFling(available)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Velocity.flingItemCount(
|
||||
isVertical: Boolean,
|
||||
itemSize: Int,
|
||||
decay: DecayAnimationSpec<Float>,
|
||||
reverseLayout: Boolean,
|
||||
): Int {
|
||||
if (itemSize <= 0) return 0
|
||||
val velocity = if (isVertical) y else x
|
||||
val targetValue = decay.calculateTargetValue(0f, velocity)
|
||||
val flingItemCount = (targetValue / itemSize).toInt()
|
||||
return if (reverseLayout) -flingItemCount else flingItemCount
|
||||
}
|
||||
|
||||
private class WheelPickerContentScopeImpl(
|
||||
override val state: FWheelPickerState,
|
||||
) : FWheelPickerContentScope
|
||||
|
||||
private class FWheelPickerContentWrapperScopeImpl(
|
||||
private val contentScope: FWheelPickerContentScope
|
||||
) : FWheelPickerContentWrapperScope {
|
||||
lateinit var content: @Composable FWheelPickerContentScope.(index: Int) -> Unit
|
||||
|
||||
override val state: FWheelPickerState get() = contentScope.state
|
||||
|
||||
@Composable
|
||||
override fun content(index: Int) {
|
||||
contentScope.content(index)
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun logMsg(debug: Boolean, block: () -> String) {
|
||||
if (debug) {
|
||||
println("FWheelPicker" + block())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.sd.lib.compose.wheel_picker
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* The default implementation of focus view in vertical.
|
||||
*/
|
||||
@Composable
|
||||
fun FWheelPickerFocusVertical(
|
||||
modifier: Modifier = Modifier,
|
||||
dividerSize: Dp = 1.dp,
|
||||
dividerColor: Color = DefaultDividerColor,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize()
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(dividerColor)
|
||||
.height(dividerSize)
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.TopCenter),
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(dividerColor)
|
||||
.height(dividerSize)
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of focus view in horizontal.
|
||||
*/
|
||||
@Composable
|
||||
fun FWheelPickerFocusHorizontal(
|
||||
modifier: Modifier = Modifier,
|
||||
dividerSize: Dp = 1.dp,
|
||||
dividerColor: Color = DefaultDividerColor,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize()
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(dividerColor)
|
||||
.width(dividerSize)
|
||||
.fillMaxHeight()
|
||||
.align(Alignment.CenterStart),
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(dividerColor)
|
||||
.width(dividerSize)
|
||||
.fillMaxHeight()
|
||||
.align(Alignment.CenterEnd),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default divider color.
|
||||
*/
|
||||
private val DefaultDividerColor: Color
|
||||
@Composable
|
||||
get() = (if (isSystemInDarkTheme()) {
|
||||
Color.White
|
||||
} else {
|
||||
Color.Black
|
||||
}).copy(alpha = 0.2f)
|
||||
|
||||
/**
|
||||
* Default content wrapper.
|
||||
*/
|
||||
val DefaultWheelPickerContentWrapper: @Composable FWheelPickerContentWrapperScope.(index: Int) -> Unit
|
||||
get() = { index ->
|
||||
val isFocus = index == state.currentIndexSnapshot
|
||||
val targetAlpha = if (isFocus) 1.0f else 0.3f
|
||||
val targetScale = if (isFocus) 1.0f else 0.8f
|
||||
val animateScale by animateFloatAsState(targetScale)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
this.alpha = targetAlpha
|
||||
this.scaleX = animateScale
|
||||
this.scaleY = animateScale
|
||||
}
|
||||
) {
|
||||
content(index)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package com.sd.lib.compose.wheel_picker
|
||||
|
||||
import androidx.compose.foundation.MutatePriority
|
||||
import androidx.compose.foundation.gestures.ScrollScope
|
||||
import androidx.compose.foundation.gestures.ScrollableState
|
||||
import androidx.compose.foundation.interaction.InteractionSource
|
||||
import androidx.compose.foundation.lazy.LazyListItemInfo
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.listSaver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@Composable
|
||||
fun rememberFWheelPickerState(
|
||||
initialIndex: Int = 0,
|
||||
): FWheelPickerState = rememberSaveable(saver = FWheelPickerState.Saver) {
|
||||
FWheelPickerState(
|
||||
initialIndex = initialIndex,
|
||||
)
|
||||
}
|
||||
|
||||
class FWheelPickerState(
|
||||
initialIndex: Int = 0,
|
||||
) : ScrollableState {
|
||||
|
||||
internal var debug = false
|
||||
internal val lazyListState = LazyListState()
|
||||
|
||||
private var _currentIndex by mutableStateOf(-1)
|
||||
private var _currentIndexSnapshot by mutableStateOf(-1)
|
||||
|
||||
private var _pendingIndex: Int? = initialIndex
|
||||
set(value) {
|
||||
field = value
|
||||
if (value == null) resumeAwaitScroll()
|
||||
}
|
||||
private var _pendingIndexContinuation: Continuation<Unit>? = null
|
||||
|
||||
private var _count = 0
|
||||
set(value) {
|
||||
field = value.coerceAtLeast(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Index of picker when it is idle.
|
||||
*
|
||||
* Note that this property is observable and if you use it in the composable function
|
||||
* it will be recomposed on every change.
|
||||
*/
|
||||
val currentIndex: Int
|
||||
get() = _currentIndex
|
||||
|
||||
/**
|
||||
* Index of picker when it is idle or drag but not fling.
|
||||
*
|
||||
* Note that this property is observable and if you use it in the composable function
|
||||
* it will be recomposed on every change.
|
||||
*/
|
||||
val currentIndexSnapshot: Int
|
||||
get() = _currentIndexSnapshot
|
||||
|
||||
val interactionSource: InteractionSource
|
||||
get() = lazyListState.interactionSource
|
||||
|
||||
val hasPendingScroll: Boolean
|
||||
get() = _pendingIndex != null
|
||||
|
||||
suspend fun animateScrollToIndex(
|
||||
index: Int,
|
||||
) {
|
||||
logMsg(debug) { "animateScrollToIndex index:$index" }
|
||||
|
||||
val safeIndex = index.coerceAtLeast(0)
|
||||
lazyListState.animateScrollToItem(safeIndex)
|
||||
synchronizeCurrentIndex()
|
||||
}
|
||||
|
||||
suspend fun scrollToIndex(
|
||||
index: Int,
|
||||
pending: Boolean = true,
|
||||
) {
|
||||
logMsg(debug) { "scrollToIndex index:$index pending:$pending" }
|
||||
|
||||
val safeIndex = index.coerceAtLeast(0)
|
||||
lazyListState.scrollToItem(safeIndex)
|
||||
synchronizeCurrentIndex()
|
||||
|
||||
if (pending) {
|
||||
awaitScroll(safeIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun awaitScroll(index: Int) {
|
||||
if (_currentIndex == index) return
|
||||
logMsg(debug) { "awaitScroll index $index start" }
|
||||
|
||||
// Resume last continuation before suspend.
|
||||
resumeAwaitScroll()
|
||||
|
||||
_pendingIndex = index
|
||||
suspendCancellableCoroutine {
|
||||
_pendingIndexContinuation = it
|
||||
it.invokeOnCancellation {
|
||||
logMsg(debug) { "awaitScroll index $index canceled" }
|
||||
_pendingIndexContinuation = null
|
||||
_pendingIndex = null
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
logMsg(debug) { "awaitScroll index $index finish" }
|
||||
}
|
||||
|
||||
private fun resumeAwaitScroll() {
|
||||
_pendingIndexContinuation?.let {
|
||||
logMsg(debug) { "resumeAwaitScroll pendingIndex:$_pendingIndex" }
|
||||
it.resume(Unit)
|
||||
_pendingIndexContinuation = null
|
||||
}
|
||||
}
|
||||
|
||||
internal suspend fun notifyCountChanged(count: Int) {
|
||||
logMsg(debug) { "notifyCountChanged count:$count currentIndex:$_currentIndex pendingIndex:$_pendingIndex" }
|
||||
|
||||
_count = count
|
||||
|
||||
val maxIndex = count - 1
|
||||
if (_currentIndex > maxIndex) {
|
||||
setCurrentIndexInternal(maxIndex)
|
||||
} else {
|
||||
_pendingIndex?.let { pendingIndex ->
|
||||
if (count > pendingIndex) {
|
||||
scrollToIndex(pendingIndex, pending = false)
|
||||
}
|
||||
}
|
||||
if (_currentIndex < 0) {
|
||||
synchronizeCurrentIndex()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun synchronizeCurrentIndex() {
|
||||
logMsg(debug) { "synchronizeCurrentIndex" }
|
||||
val index = synchronizeCurrentIndexSnapshot()
|
||||
setCurrentIndexInternal(index)
|
||||
}
|
||||
|
||||
private fun setCurrentIndexInternal(index: Int) {
|
||||
val safeIndex = index.coerceAtLeast(-1)
|
||||
if (_currentIndex != safeIndex) {
|
||||
logMsg(debug) { "Current index changed $safeIndex" }
|
||||
_currentIndex = safeIndex
|
||||
_currentIndexSnapshot = safeIndex
|
||||
if (_pendingIndex == safeIndex) {
|
||||
_pendingIndex = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun synchronizeCurrentIndexSnapshot(): Int {
|
||||
return (mostStartItemInfo()?.index ?: -1).also {
|
||||
_currentIndexSnapshot = it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The item closest to the viewport start.
|
||||
*/
|
||||
private fun mostStartItemInfo(): LazyListItemInfo? {
|
||||
if (_count <= 0) return null
|
||||
|
||||
val layoutInfo = lazyListState.layoutInfo
|
||||
val listInfo = layoutInfo.visibleItemsInfo
|
||||
|
||||
if (listInfo.isEmpty()) return null
|
||||
if (listInfo.size == 1) return listInfo.first()
|
||||
|
||||
val firstItem = listInfo.first()
|
||||
val firstOffsetDelta = (firstItem.offset - layoutInfo.viewportStartOffset).absoluteValue
|
||||
return if (firstOffsetDelta < firstItem.size / 2) {
|
||||
firstItem
|
||||
} else {
|
||||
listInfo[1]
|
||||
}
|
||||
}
|
||||
|
||||
override val isScrollInProgress: Boolean
|
||||
get() = lazyListState.isScrollInProgress
|
||||
|
||||
override suspend fun scroll(
|
||||
scrollPriority: MutatePriority,
|
||||
block: suspend ScrollScope.() -> Unit,
|
||||
) {
|
||||
lazyListState.scroll(scrollPriority, block)
|
||||
}
|
||||
|
||||
override fun dispatchRawDelta(delta: Float): Float {
|
||||
return lazyListState.dispatchRawDelta(delta)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Saver: Saver<FWheelPickerState, *> = listSaver(
|
||||
save = {
|
||||
listOf<Any>(
|
||||
it.currentIndex,
|
||||
)
|
||||
},
|
||||
restore = {
|
||||
FWheelPickerState(
|
||||
initialIndex = it[0] as Int,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user