Clean up the questDetail parallax

This commit is contained in:
Thomas Andres Gomez 2023-08-02 09:05:04 +02:00
parent df5b1ba59c
commit 39c3b27c36
5 changed files with 49 additions and 88 deletions

View file

@ -1,35 +0,0 @@
package com.pixelized.rplexicon.ui.composable.remember
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
/**
* https://stackoverflow.com/questions/73333935/current-scroll-position-value-in-pixels-in-lazycolumn-jetpack-compose
*/
@Composable
fun rememberCurrentOffset(state: LazyListState): State<Int> {
val position = remember { derivedStateOf { state.firstVisibleItemIndex } }
val itemOffset = remember { derivedStateOf { state.firstVisibleItemScrollOffset } }
val lastPosition = rememberPrevious(position.value)
val lastItemOffset = rememberPrevious(itemOffset.value)
val currentOffset = remember { mutableStateOf(0) }
LaunchedEffect(position.value, itemOffset.value) {
if (lastPosition == null || position.value == 0) {
currentOffset.value = itemOffset.value
} else if (lastPosition == position.value) {
currentOffset.value += (itemOffset.value - (lastItemOffset ?: 0))
} else if (lastPosition > position.value) {
currentOffset.value -= (lastItemOffset ?: 0)
} else { // lastPosition.value < position.value
currentOffset.value += itemOffset.value
}
}
return currentOffset
}

View file

@ -0,0 +1,39 @@
package com.pixelized.rplexicon.ui.composable.remember
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@Stable
data class LazyListOffset(
val offsetY: State<Dp>,
val connection: NestedScrollConnection,
)
@Composable
@Stable
fun rememberLazyListOffset(): LazyListOffset {
val density = LocalDensity.current
return remember {
val offsetY = mutableStateOf(0.dp)
LazyListOffset(
offsetY = offsetY,
connection = object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
offsetY.value -= with(density) { available.y.toDp() }
return Offset.Zero
}
},
)
}
}

View file

@ -1,21 +0,0 @@
package com.pixelized.rplexicon.ui.composable.remember
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
@Composable
fun <T> rememberPrevious(
current: T,
shouldUpdate: (prev: T?, curr: T) -> Boolean = { a: T?, b: T -> a != b },
): T? {
val ref = rememberRef<T>()
// launched after render, so the current render will have the old value anyway
SideEffect {
if (shouldUpdate(ref.value, current)) {
ref.value = current
}
}
return ref.value
}

View file

@ -1,23 +0,0 @@
package com.pixelized.rplexicon.ui.composable.remember
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.remember
/**
* Returns a dummy MutableState that does not cause render when setting it
*/
@Composable
fun <T> rememberRef(): MutableState<T?> {
// for some reason it always recreated the value with vararg keys,
// leaving out the keys as a parameter for remember for now
return remember {
object : MutableState<T?> {
override var value: T? = null
override fun component1(): T? = value
override fun component2(): (T?) -> Unit = { value = it }
}
}
}

View file

@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@ -36,8 +35,8 @@ import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
@ -52,7 +51,8 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.rplexicon.R import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.ui.composable.BackgroundImage import com.pixelized.rplexicon.ui.composable.BackgroundImage
import com.pixelized.rplexicon.ui.composable.remember.rememberCurrentOffset import com.pixelized.rplexicon.ui.composable.remember.LazyListOffset
import com.pixelized.rplexicon.ui.composable.remember.rememberLazyListOffset
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.ui.theme.LexiconTheme
import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.lexicon
@ -179,14 +179,17 @@ private fun QuestDetailContent(
) )
}, },
content = { padding -> content = { padding ->
val lazyListOffset = rememberLazyListOffset()
Surface( Surface(
modifier = Modifier.padding(padding), modifier = Modifier
.padding(padding)
.nestedScroll(lazyListOffset.connection),
) { ) {
BackgroundImage( BackgroundImage(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.aspectRatio(ratio = 1f) .aspectRatio(ratio = 1f)
.scrollOffset(scrollState = state) { -it / 2 }, .scrollOffset(scrollState = lazyListOffset) { -it / 2 },
model = { annotatedQuest.background }, model = { annotatedQuest.background },
) )
LazyColumn( LazyColumn(
@ -327,12 +330,10 @@ private fun QuestDetailContent(
@Stable @Stable
private fun Modifier.scrollOffset( private fun Modifier.scrollOffset(
scrollState: LazyListState, scrollState: LazyListOffset,
block: (Dp) -> Dp block: (Dp) -> Dp
): Modifier = composed { ): Modifier = composed {
val scroll = rememberCurrentOffset(scrollState) this.offset(y = block(scrollState.offsetY.value))
val density = LocalDensity.current
this.offset(y = with(density) { block(scroll.value.toDp()) })
} }
@Composable @Composable