diff --git a/Sources/SkipUI/SkipUI/Containers/Navigation.swift b/Sources/SkipUI/SkipUI/Containers/Navigation.swift index a2708244..8b0414eb 100644 --- a/Sources/SkipUI/SkipUI/Containers/Navigation.swift +++ b/Sources/SkipUI/SkipUI/Containers/Navigation.swift @@ -38,6 +38,7 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.saveable.Saver import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.unit.dp import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.text.style.TextOverflow @@ -115,13 +116,21 @@ public struct NavigationStack : View where Root: View { let preferenceUpdates = remember { mutableStateOf(0) } let _ = preferenceUpdates.value // Read so that it can trigger recompose on change - let title = rememberSaveable(stateSaver: context.stateSaver as! Saver) { mutableStateOf(NavigationTitlePreferenceKey.defaultValue) } + let uncomposedTitle = "__UNCOMPOSED__" + let title = rememberSaveable(stateSaver: context.stateSaver as! Saver) { mutableStateOf(uncomposedTitle) } + + let scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) + var modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection).then(context.modifier) + // Perform an invisible compose pass to gather preference information. Otherwise we may see the content render one way, then + // immediately re-render with an updated top bar + if title.value == uncomposedTitle { + modifier = modifier.alpha(Float(0.0)) + } // We place the top bar scaffold within each entry rather than at the navigation controller level. There isn't a fluid animation // between navigation bar states on Android, and it is simpler to only hoist navigation bar preferences to this level - let scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) Scaffold( - modifier: Modifier.nestedScroll(scrollBehavior.nestedScrollConnection).then(context.modifier), + modifier: modifier, topBar: { guard !isRoot || !title.value.isEmpty else { return @@ -154,6 +163,9 @@ public struct NavigationStack : View where Root: View { content(context.content()) } } + if title.value == uncomposedTitle { + title.value = NavigationTitlePreferenceKey.defaultValue + } } } #else diff --git a/Sources/SkipUI/SkipUI/Containers/TabView.swift b/Sources/SkipUI/SkipUI/Containers/TabView.swift index bb7869ca..1408409f 100644 --- a/Sources/SkipUI/SkipUI/Containers/TabView.swift +++ b/Sources/SkipUI/SkipUI/Containers/TabView.swift @@ -23,7 +23,6 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController - #endif public struct TabView : View where Content : View { @@ -94,9 +93,6 @@ public struct TabView : View where Content : View { // Use a constant number of routes. Changing routes causes a NavHost to reset its state for tabIndex in 0..<100 { composable(String(describing: tabIndex)) { - guard tabIndex < tabCount else { - return - } Box(modifier: Modifier.padding(padding).fillMaxSize(), contentAlignment: androidx.compose.ui.Alignment.Center) { // Use a custom composer to only render the tabIndex'th view var composeIndex = 0