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"))
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