Travis Griggs
02/27/2023, 5:18 PMTravis Griggs
02/27/2023, 5:20 PMclass MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Pager4Theme {
MainScreen()
}
}
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun MainScreen() {
val navController = rememberAnimatedNavController()
Scaffold(bottomBar = {
PageTabBar(modifier = Modifier,
onSelect = { index -> navController.navigate("page_$index") })
}) { innerPadding ->
PagesNavHost(
navController = navController, modifier = Modifier.padding(innerPadding)
)
}
}
// This feels ugly, I had the same block of code for both transitions nearly, so I figured out how to
// extract it, but passing a "scope" feels odd
@OptIn(ExperimentalAnimationApi::class)
private fun slideDirection(scope: AnimatedContentScope<NavBackStackEntry>): AnimatedContentScope.SlideDirection {
val initialRoute = scope.initialState.destination.route ?: ""
val targetRoute = scope.targetState.destination.route ?: ""
return if (initialRoute < targetRoute) {
AnimatedContentScope.SlideDirection.Left
} else {
AnimatedContentScope.SlideDirection.Right
}
}
// There's an open question (to me at least) of why I'm using the whole Nav thing here
// I did it because that seemed the way to have separate "screens" and get side to side animation
// But they're not really a stack? Maybe that doesn't matter. But could I just activate one of four
// child composables and accomplish the side-to-side animation a different way?
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun PagesNavHost(
modifier: Modifier = Modifier,
navController: NavHostController,
startDestination: String = "page_1"
) {
AnimatedNavHost(modifier = modifier.fillMaxSize(),
navController = navController,
startDestination = startDestination,
enterTransition = { slideIntoContainer(slideDirection(this), animationSpec = tween(250)) },
exitTransition = {
slideOutOfContainer(
slideDirection(this),
animationSpec = tween(250)
)
}) {
composable("page_1") { PlansPage() }
composable("page_2") { MapsPage() }
composable("page_3") { StatusPage() }
composable("page_4") { SettingsPage() }
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
Pager4Theme {
MainScreen()
}
Travis Griggs
02/27/2023, 5:20 PM// TODO: Figure out the Right/New Way(tm) to do the named colors
@Composable
fun PageTabButton(
text: String,
vector: Int,
index: Int,
selectedIndex: MutableState<Int>,
modifier: Modifier = Modifier
) {
val isSelected by remember { derivedStateOf { index == selectedIndex.value } }
val tintColor by animateColorAsState(
targetValue = when (isSelected) {
true -> Color.White; false -> colorResource(id = R.color.label_tabs_inactive)
}
)
Column(
modifier = modifier
.padding(6.dp)
.clickable { selectedIndex.value = index },
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
modifier = Modifier.size(24.dp),
painter = painterResource(id = vector),
contentDescription = text,
colorFilter = ColorFilter.tint(tintColor)
)
Spacer(modifier = Modifier.height(4.dp))
val weight = when (isSelected) {
true -> FontWeight.Medium; false -> FontWeight.Normal
}
Text(
text = text, color = tintColor, fontSize = 11.sp, fontWeight = weight
)
}
}
// My hunch is that I'm working too hard with this selectedIndex thing
// I see that Modifier has selectable stuff, I should of course add that for accessability,
// but the real question is, can it actually model the state of which button is selected for me as well?
@Composable
fun PageTabBar(
modifier: Modifier = Modifier, onSelect: (Int) -> Unit = { _ -> }
) {
Row(
modifier = modifier
.background(color = colorResource(id = R.color.background_tabs))
.fillMaxWidth()
) {
var selectedIndex = remember { mutableStateOf(1) }
LaunchedEffect(selectedIndex.value) {
onSelect(selectedIndex.value)
}
val fillEach = Modifier.weight(1f, true) // Is this REALLY how I get even distribution?
// CAN I do the following with a loop?
PageTabButton(
text = "PLANS",
vector = R.drawable.tab_plans_mask,
index = 1,
selectedIndex = selectedIndex,
modifier = fillEach
)
PageTabButton(
text = "MAP",
vector = R.drawable.tab_map_mask,
index = 2,
selectedIndex = selectedIndex,
modifier = fillEach
)
PageTabButton(
text = "STATUS",
vector = R.drawable.tab_status_mask,
index = 3,
selectedIndex = selectedIndex,
modifier = fillEach
)
PageTabButton(
text = "SETTINGS",
vector = R.drawable.tab_settings_mask,
index = 4,
selectedIndex = selectedIndex,
modifier = fillEach
)
}
}
@Preview(showBackground = true)
@Composable
fun PageTabBarPreview() {
Pager4Theme {
PageTabBar()
}
}
Travis Griggs
02/27/2023, 5:21 PMTravis Griggs
02/27/2023, 5:22 PMdorche
02/27/2023, 8:21 PM