Reputation: 7271
I have two UI states: FIRST
and SECOND
. In the FIRST
state, I have a HorizontalPager
and other widgets. In the SECOND
state, I have a simple Text
widget. I am switching between the UI states with a Button
click.
I want to save the index of the current page in the HorizontalPager
when I switch to the SECOND
state, so that when I switch back to the FIRST
state, the HorizontalPager
opens on the same page.
For example, if I am on page 3 of the HorizontalPager
and I click the Button
to switch to the SECOND
state, I want the HorizontalPager
to open on page 3 when I switch back to the FIRST
state.
Currently, when I switch back to the FIRST
state, the HorizontalPager
always opens on page 0.
Note: The current page index of the HorizontalPager is only saved while the activity is active. This means that if the activity is destroyed (for example, when the user close the application or move to another activity), the HorizontalPager will start on page 0 when the activity is recreated.
MainActivity
class MainActivity : ComponentActivity() {
@OptIn(ExperimentalFoundationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ViewObersableTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
val pagerState = rememberPagerState()
SaveVariable(pagerState, VariableViewModel())
}
}
}
}
}
SaveVariable
@Composable
@OptIn(ExperimentalFoundationApi::class)
fun SaveVariable(pagerState: PagerState, viewModel: VariableViewModel) {
LaunchedEffect(key1 = pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
viewModel.currentIndex = page
}
}
LaunchedEffect(key1 = viewModel.setLastCurrentPage) {
Log.e(">> LaunchedEffect", "${viewModel.currentIndex}")
}
SaveVariableItem(viewModel.currentIndex, viewModel.uiState, pagerState) {
viewModel.changeUIi()
}
}
VariableViewModel
class VariableViewModel : ViewModel() {
var uiState by mutableStateOf(ScreenName.FIRST)
var currentIndex by mutableStateOf(0)
var setLastCurrentPage by mutableStateOf(false)
fun changeUIi() {
uiState = if (uiState == ScreenName.FIRST) {
setLastCurrentPage = true
ScreenName.SECOND
} else {
setLastCurrentPage = false
ScreenName.FIRST
}
}
}
ScreenName
enum class ScreenName {
FIRST,
SECOND
}
SaveVariableItem
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SaveVariableItem(
currentIndex: Int,
uiState: ScreenName,
pagerState: PagerState,
changeUiState: () -> Unit,
) {
Column {
when (uiState) {
ScreenName.FIRST -> {
ScreenFirstView(pagerState)
}
ScreenName.SECOND -> {
ScreenSecondView(currentIndex, "SECOND")
}
}
ChangeUiStateButton(changeUiState)
}
}
ChangeUiStateButton
@Composable
fun ChangeUiStateButton(changeUiState: () -> Unit) {
Button(onClick = { changeUiState() }) {
Text(text = "Add")
}
}
ScreenFirstView
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ScreenFirstView(pagerState: PagerState) {
Column(
modifier = Modifier
.wrapContentSize()
.background(Color.Black)
) {
HorizontalPager(
modifier = Modifier.padding(20.dp),
pageCount = 10,
state = pagerState
) { page ->
Text(
text = "Page: $page",
modifier = Modifier.fillMaxWidth(),
color = Color.White
)
}
}
}
ScreenSecondView
@Composable
fun ScreenSecondView(currentIndex: Int, screenImage: String) {
Column(
modifier = Modifier
.wrapContentSize()
.background(Color.Black)
) {
Text(text = "$currentIndex ==== $screenImage", color = Color.White)
}
}
My github sample is here.
implementation(platform("androidx.compose:compose-bom:2023.05.01"))
Upvotes: 2
Views: 1508
Reputation: 93
Ive gotten this to work using state flows in the ViewModel. I cut the code down a little, but basically i had to add a LaunchedEffect into the composable containing the pager to update the PagerState upon composition using the saved page number in ViewModel. Not sure if there is a better way to accomplish this but this does work. heres the modified repo: https://github.com/Mr0btain/SavePagerState
Upvotes: 1