Clean up the questDetail parallax
This commit is contained in:
		
							parent
							
								
									df5b1ba59c
								
							
						
					
					
						commit
						39c3b27c36
					
				
					 5 changed files with 49 additions and 88 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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 }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.height
 | 
			
		|||
import androidx.compose.foundation.layout.offset
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyListState
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.foundation.lazy.rememberLazyListState
 | 
			
		||||
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.ColorFilter
 | 
			
		||||
import androidx.compose.ui.graphics.graphicsLayer
 | 
			
		||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
 | 
			
		||||
import androidx.compose.ui.layout.ContentScale
 | 
			
		||||
import androidx.compose.ui.platform.LocalDensity
 | 
			
		||||
import androidx.compose.ui.res.painterResource
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.text.AnnotatedString
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +51,8 @@ import androidx.compose.ui.unit.dp
 | 
			
		|||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import com.pixelized.rplexicon.R
 | 
			
		||||
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.theme.LexiconTheme
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
			
		||||
| 
						 | 
				
			
			@ -179,14 +179,17 @@ private fun QuestDetailContent(
 | 
			
		|||
            )
 | 
			
		||||
        },
 | 
			
		||||
        content = { padding ->
 | 
			
		||||
            val lazyListOffset = rememberLazyListOffset()
 | 
			
		||||
            Surface(
 | 
			
		||||
                modifier = Modifier.padding(padding),
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(padding)
 | 
			
		||||
                    .nestedScroll(lazyListOffset.connection),
 | 
			
		||||
            ) {
 | 
			
		||||
                BackgroundImage(
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxWidth()
 | 
			
		||||
                        .aspectRatio(ratio = 1f)
 | 
			
		||||
                        .scrollOffset(scrollState = state) { -it / 2 },
 | 
			
		||||
                        .scrollOffset(scrollState = lazyListOffset) { -it / 2 },
 | 
			
		||||
                    model = { annotatedQuest.background },
 | 
			
		||||
                )
 | 
			
		||||
                LazyColumn(
 | 
			
		||||
| 
						 | 
				
			
			@ -327,12 +330,10 @@ private fun QuestDetailContent(
 | 
			
		|||
 | 
			
		||||
@Stable
 | 
			
		||||
private fun Modifier.scrollOffset(
 | 
			
		||||
    scrollState: LazyListState,
 | 
			
		||||
    scrollState: LazyListOffset,
 | 
			
		||||
    block: (Dp) -> Dp
 | 
			
		||||
): Modifier = composed {
 | 
			
		||||
    val scroll = rememberCurrentOffset(scrollState)
 | 
			
		||||
    val density = LocalDensity.current
 | 
			
		||||
    this.offset(y = with(density) { block(scroll.value.toDp()) })
 | 
			
		||||
    this.offset(y = block(scrollState.offsetY.value))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue