Fixed
Status Update
Comments
cl...@google.com <cl...@google.com>
ap...@google.com <ap...@google.com> #2
Project: platform/frameworks/support
Branch: androidx-master-dev
commit d0a10be065a3a629e3835f28d35804c91d8d2e4d
Author: Ian Lake <ilake@google.com>
Date: Mon Sep 14 16:10:06 2020
Mention the current destination in getBackStackEntry errors
Improve the debugging experience for "No destination
with ID..." errors in getBackStackEntry() by mentioning
exactly destination the NavController is on. This would
allow developers to know if they have called popBackStack()
to a destination they don't expect to be at or if
they have not called setGraph() at all (where the
current destination would be null).
Test: existing tests pass
BUG: 168311416
Change-Id: Ia96b6732d7caadbddf31b7f35a1a419407ff6e25
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java
https://android-review.googlesource.com/1427352
Branch: androidx-master-dev
commit d0a10be065a3a629e3835f28d35804c91d8d2e4d
Author: Ian Lake <ilake@google.com>
Date: Mon Sep 14 16:10:06 2020
Mention the current destination in getBackStackEntry errors
Improve the debugging experience for "No destination
with ID..." errors in getBackStackEntry() by mentioning
exactly destination the NavController is on. This would
allow developers to know if they have called popBackStack()
to a destination they don't expect to be at or if
they have not called setGraph() at all (where the
current destination would be null).
Test: existing tests pass
BUG: 168311416
Change-Id: Ia96b6732d7caadbddf31b7f35a1a419407ff6e25
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java
cl...@google.com <cl...@google.com> #3
We've updated the error message to make it more clear what destination you're currently on - this will help you determine if your call to setGraph()
hasn't happened yet (you have a null current destination) or if you've popped to another destination unexpectedly.
ap...@google.com <ap...@google.com> #4
Project: platform/frameworks/support
Branch: snap-temp-L69500000699825513
commit 6ada6bd039f4a28d2760f4912093abc60ab54d84
Author: Ian Lake <ilake@google.com>
Date: Mon Sep 14 16:10:06 2020
Mention the current destination in getBackStackEntry errors
Improve the debugging experience for "No destination
with ID..." errors in getBackStackEntry() by mentioning
exactly destination the NavController is on. This would
allow developers to know if they have called popBackStack()
to a destination they don't expect to be at or if
they have not called setGraph() at all (where the
current destination would be null).
Test: existing tests pass
BUG: 168311416
Change-Id: Ia96b6732d7caadbddf31b7f35a1a419407ff6e25
(cherry picked from commit d0a10be065a3a629e3835f28d35804c91d8d2e4d)
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java
https://android-review.googlesource.com/1436733
Branch: snap-temp-L69500000699825513
commit 6ada6bd039f4a28d2760f4912093abc60ab54d84
Author: Ian Lake <ilake@google.com>
Date: Mon Sep 14 16:10:06 2020
Mention the current destination in getBackStackEntry errors
Improve the debugging experience for "No destination
with ID..." errors in getBackStackEntry() by mentioning
exactly destination the NavController is on. This would
allow developers to know if they have called popBackStack()
to a destination they don't expect to be at or if
they have not called setGraph() at all (where the
current destination would be null).
Test: existing tests pass
BUG: 168311416
Change-Id: Ia96b6732d7caadbddf31b7f35a1a419407ff6e25
(cherry picked from commit d0a10be065a3a629e3835f28d35804c91d8d2e4d)
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java
Description
Devices/Android versions reproduced on: API 33
Animation is broken when navigating between two NavGraphs while using the NavOption popUpTo(0) { inclusive = true }. Not a problem when val zIndex = composeNavigator.backStack.value.size.toFloat() as NavHost returns increasing indices for subsequent screens.
However, when popping all back stack entries, the index for the next screen is reset to 1.0 at some point resulting in the broken animation. Attached video of broken animation.
Repro code
```
package com.example.myapplication
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.*
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.navigation
import com.example.myapplication.ui.theme.MyApplicationTheme
import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.composable
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import org.w3c.dom.Text
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface {
MyNavHost()
}
}
}
}
}
val SUBGRAPH1 = "Subgraph1"
val FIRSTVIEW1 = "FirstView1"
val SECONDVIEW1 = "SecondView1"
val SUBGRAPH2 = "Subgraph2"
val FIRSTVIEW2 = "FirstView2"
val SECONDVIEW2 = "SecondView2"
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun MyNavHost() {
val navController = rememberAnimatedNavController()
val durationMillis = 1500
val offsetAnimationSpec: FiniteAnimationSpec<IntOffset> = remember { tween(durationMillis) }
val floatAnimationSpec: FiniteAnimationSpec<Float> = remember { tween(durationMillis) }
// the start destination is always the welcome screen so we can popToRoot at any time
// only when a user is set, we navigate to the map directly without animation
AnimatedNavHost(
navController = navController,
startDestination = SUBGRAPH1,
enterTransition = {
slideInHorizontally(
initialOffsetX = { it / 2 },
animationSpec = offsetAnimationSpec
) + fadeIn(animationSpec = floatAnimationSpec)
},
exitTransition = {
slideOutHorizontally(
targetOffsetX = { -it / 2 },
animationSpec = offsetAnimationSpec
)
},
popEnterTransition = {
slideInHorizontally(
initialOffsetX = { -it / 2 },
animationSpec = offsetAnimationSpec
)
},
popExitTransition = {
slideOutHorizontally(
targetOffsetX = { it / 2 },
animationSpec = offsetAnimationSpec
) + fadeOut(animationSpec = floatAnimationSpec)
},
modifier = Modifier.fillMaxSize()
) {
navGraph1(navController)
navGraph2(navController)
}
}
@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.navGraph1(
navController: NavController
) {
navigation(
startDestination = FIRSTVIEW1,
route = SUBGRAPH1
) {
composable(FIRSTVIEW1) {
PlaceholderComposable(
text = FIRSTVIEW1,
color = Color.Green,
onNext = { navController.navigate(SECONDVIEW1) }
)
}
composable(SECONDVIEW1) {
PlaceholderComposable(
text = SECONDVIEW1,
color = Color.Red,
onNext = { navController.navigate(SUBGRAPH2) },
onPrevious = { navController.navigateUp() }
)
}
}
}
@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.navGraph2(
navController: NavController
) {
navigation(
startDestination = FIRSTVIEW2,
route = SUBGRAPH2
) {
composable(FIRSTVIEW2) {
PlaceholderComposable(
text = FIRSTVIEW2,
color = Color.Yellow,
onNext = {
navController.navigate(SECONDVIEW2) {
popUpTo(0) { inclusive = true }
}
},
onPrevious = { navController.navigateUp() }
)
}
composable(SECONDVIEW2) {
PlaceholderComposable(
text = SECONDVIEW2,
color = Color.Blue,
onNext = {
navController.navigate(SUBGRAPH1) {
popUpTo(0) { inclusive = true }
}
}
)
}
}
}
@Composable
fun PlaceholderComposable(
text: String,
color: Color,
onNext: (() -> Unit)? = null,
onPrevious: (() -> Unit)? = null
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(color),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = text)
Row {
onPrevious?.let { callback ->
Button(
onClick = { callback() },
modifier = Modifier.padding(8.dp)
) {
Text(text = "Previous")
}
}
onNext?.let { callback ->
Button(
onClick = { callback() },
modifier = Modifier.padding(8.dp)
) {
Text(text = "Next")
}
}
}
}
}
```
Steps to repro
1. click "next"
2. click "previous"
3. click "next"
4. click "next"
5. click "next"