I'd like to use Toolbar with Jetpack Compose. Does it have such a Composable component?
You can use the TopAppBar.
The best way is to use it with the Scaffold. Something like:
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "TopAppBar")
},
navigationIcon = {
IconButton(onClick = { }) {
Icon(Icons.Filled.Menu,"")
}
},
backgroundColor = Color.Blue,
contentColor = Color.White,
elevation = 12.dp
)
}, content = {
})
Using
compose_version = '1.0.0-beta01'
TopAppBar(
title = {
Text(text = "Pets Show")
},
navigationIcon = {
IconButton(onClick = { }) {
Icon(imageVector = Icons.Filled.Menu, contentDescription = "Menu Btn")
}
},
backgroundColor = Color.Transparent,
contentColor = Color.Gray,
elevation = 2.dp
)
TopAppBar is a pre-defined composable that will help you accomplish what you want. You can use it with Scaffold in order to get basic material design scaffolding to hook up the TopAppBar.
Here is an example with detailed comments to see how to use it - https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example/blob/1f843cb2bf18b9988a0dfc611b631f216f02149e/app/src/main/java/com/example/jetpackcompose/material/FixedActionButtonActivity.kt#L70
Copying it here to make it easy to consume
// Scaffold is a pre-defined composable that implements the basic material design visual
// layout structure. It takes in child composables for all the common elements that you see
// in an app using material design - app bar, bottom app bar, floating action button, etc. It
// also takes care of laying out these child composables in the correct positions - eg bottom
// app bar is automatically placed at the bottom of the screen even though I didn't specify
// that explicitly.
Scaffold(
scaffoldState = scaffoldState,
topAppBar = { TopAppBar(title = { Text("Scaffold Examples") }) },
bottomAppBar = { fabConfiguration ->
// We specify the shape of the FAB bu passing a shape composable (fabShape) as a
// parameter to cutoutShape property of the BottomAppBar. It automatically creates a
// cutout in the BottomAppBar based on the shape of the Floating Action Button.
BottomAppBar(fabConfiguration = fabConfiguration, cutoutShape = fabShape) {}
},
floatingActionButton = {
FloatingActionButton(
onClick = {},
// We specify the same shape that we passed as the cutoutShape above.
shape = fabShape,
// We use the secondary color from the current theme. It uses the defaults when
// you don't specify a theme (this example doesn't specify a theme either hence
// it will just use defaults. Look at DarkModeActivity if you want to see an
// example of using themes.
backgroundColor = MaterialTheme.colors.secondary
) {
IconButton(onClick = {}) {
Icon(asset = Icons.Filled.Favorite)
}
}
},
floatingActionButtonPosition = Scaffold.FabPosition.CenterDocked,
bodyContent = { modifier ->
// Vertical scroller is a composable that adds the ability to scroll through the
// child views
VerticalScroller {
// Column is a composable that places its children in a vertical sequence. You
// can think of it similar to a LinearLayout with the vertical orientation.
Column(modifier) {
repeat(100) {
// Card composable is a predefined composable that is meant to represent
// the card surface as specified by the Material Design specification. We
// also configure it to have rounded corners and apply a modifier.
Card(color = colors[it % colors.size],
shape = RoundedCornerShape(8.dp),
modifier = Modifier.padding(8.dp)
) {
Spacer(modifier = Modifier.fillMaxWidth() + Modifier.preferredHeight(200.dp))
}
}
}
}
}
)
Yes, it's TopAppBar (in androidx.ui.material). It allows you to specify a title, color, navigation icon, and actions. See the documentation for more information.
Related
Now the icon always in the start, what should I do to align the icon to the end? I tried to use modifier but doesn't work. Thank you in advance.
If you want an Icon aligned at the end in the TopAppBar use the actions parameter instead of the navigationIcon.
Something like:
TopAppBar(
title = { Text("Simple TopAppBar") },
backgroundColor = Red,
actions = {
// RowScope here, so these icons will be placed horizontally
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Close, contentDescription = null)
}
}
)
I want to create animated bottomAppBar in jetpack compose (something like image) but Fab position in jetpack compose is only center or end and i need to move FAB to left at least, my code is :
#Composable
fun BottomBarSample() {
Scaffold(
floatingActionButton = {
FloatingActionButton(
shape = CircleShape,
onClick = {},
) {
Icon(imageVector = Icons.Filled.Add, contentDescription = "icon")
}
},
floatingActionButtonPosition = FabPosition.End,
isFloatingActionButtonDocked = true,
bottomBar = {
BottomAppBar(backgroundColor = Color.Cyan, cutoutShape = CircleShape) {
}
}
){
//body
}
}
I guess this is not a good approach as we are changing the layout direction, but you can modify the layout direction from LTR to RTL using CompositionLocalProvider
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl ) {
BottomBarSample()
}
Since there is no FabPosition.Start yet using LocalLayoutDirection is easiest way to create cutout at the beginning. Other option is to create your layout using path operations or blending modes.
In this example i show how to cut out using BlendModes but if you want elevation you need to use Path by creating shape as it's done in source code
After changing layout direction to right to left you should change direction inside content, bottomBar or other lambdas you use
#Composable
fun BottomBarSample() {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
Scaffold(
floatingActionButton = {
FloatingActionButton(
shape = CircleShape,
onClick = {},
) {
Icon(imageVector = Icons.Filled.Add, contentDescription = "icon")
}
},
floatingActionButtonPosition = FabPosition.End,
isFloatingActionButtonDocked = true,
bottomBar = {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
BottomAppBar(backgroundColor = Color.Cyan, cutoutShape = CircleShape) {
}
}
}
) {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
//body
}
}
}
}
Migrating an app in view system to Jetpack compose.
The bottom sheet scrim color is shown on the status bar in the current app.
How to reproduce the same in Jetpack compose?
Screenshot of the app using views
Screenshot of the app using compose
Compose Code
val modalBottomSheetState = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Hidden,
)
val coroutineScope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetState = modalBottomSheetState,
sheetContent = {
// Not relevant
},
) {
Scaffold(
scaffoldState = scaffoldState,
topBar = {
// Not relevant
},
floatingActionButton = {
FloatingActionButton(
onClick = {
coroutineScope.launch {
if (!modalBottomSheetState.isAnimationRunning) {
if (modalBottomSheetState.isVisible) {
modalBottomSheetState.hide()
} else {
modalBottomSheetState.show()
}
}
}
},
) {
Icon(
imageVector = Icons.Rounded.Add,
contentDescription = "Add",
)
}
},
modifier = Modifier
.fillMaxSize(),
) { innerPadding ->
// Not relevant - Nav graph code
}
}
try to use the System UI Controller in the accompanist library to control the statusBar Color and navigationBar color
implementation "com.google.accompanist:accompanist-systemuicontroller:0.18.0"
// Remember a SystemUiController
val systemUiController = rememberSystemUiController()
val useDarkIcons = MaterialTheme.colors.isLight
SideEffect {
// Update all of the system bar colors to be transparent, and use
// dark icons if we're in light theme
systemUiController.setSystemBarsColor(
color = Color.Transparent,
darkIcons = useDarkIcons
)
// setStatusBarsColor() and setNavigationBarsColor() also exist
}
In the latest versions of Compose, there's a statusBarColor parameter that is set in the Theme.kt file by default. If you're not using accompanist, try altering that value to get the desired effect.
You can remove automatic insects and make status bar transparent:
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = android.graphics.Color.TRANSPARENT;
Then draw your bottom sheet and it will go under all system bars including status bar
Just don't forget to add insects for the rest of the views when needed, it's in compose foundation now:
modifier = Modifier
.navigationBarsPadding()
.captionBarPadding()
.imePadding()
.statusBarsPadding(),
I'm building Android app with Jetpack Compose. Got stuck while trying to implement BottomAppBar with BottomDrawer pattern.
Bottom navigation drawers are modal drawers that are anchored to the bottom of the screen instead of the left or right edge. They are only used with bottom app bars. These drawers open upon tapping the navigation menu icon in the bottom app bar.
Description on material.io, and direct link to video.
I've tried using Scaffold, but it only supports side drawer. BottomDrawer appended to Scaffold content is displayed in content area and BottomDrawer doesn't cover BottomAppBar when open. Moving BottomDrawer after Scaffold function doesn't help either: BottomAppBar is covered by some invisible block and prevents clicking buttons.
I've also tried using BottomSheetScaffold, but it doesn't have BottomAppBar slot.
If Scaffold doesn't support this pattern, what would be correct way to implement it? Is it possible to extend Scaffold component? I fear that incorrect implementation from scratch might create issues later, when I'll try to implement navigation and snackbar.
I think the latest version of scaffold does have a bottom app bar parameter
They (Google Devs) invite you in the Jetpack Compose Layouts pathway to try adding other Material Design Components such as BottomNavigation or BottomDrawer to their respective Scaffold slots, and yet do not give you the solution.
BottomAppBar does have its own slot in Scaffold (i.e. bottomBar), but BottomDrawer does not - and seems to be designed exclusively for use with the BottomAppBar explicitly (see API documentation for the BottomDrawer).
At this point in the Jetpack Compose pathway, we've covered state hoisting, slots, modifiers, and have been thoroughly explained that from time to time we'll have to play around to see how best to stack and organize Composables - that they almost always have a naturally expressable way in which they work best that is practically intended.
Let me get us set up so that we are on the same page:
class MainActivity : ComponentActivity() {
#ExperimentalMaterialApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LayoutsCodelabTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
LayoutsCodelab()
}
}
}
}
}
That's the main activity calling our primary/core Composable. This is just like in the codelab with the exception of the #ExperimentalMaterialApi annotation.
Next is our primary/core Composable:
#ExperimentalMaterialApi
#Composable
fun LayoutsCodelab() {
val ( gesturesEnabled, toggleGesturesEnabled ) = remember { mutableStateOf( true ) }
val scope = rememberCoroutineScope()
val drawerState = rememberBottomDrawerState( BottomDrawerValue.Closed )
// BottomDrawer has to be the true core of our layout
BottomDrawer(
gesturesEnabled = gesturesEnabled,
drawerState = drawerState,
drawerContent = {
Button(
modifier = Modifier.align( Alignment.CenterHorizontally ).padding( top = 16.dp ),
onClick = { scope.launch { drawerState.close() } },
content = { Text( "Close Drawer" ) }
)
LazyColumn {
items( 25 ) {
ListItem(
text = { Text( "Item $it" ) },
icon = {
Icon(
Icons.Default.Favorite,
contentDescription = "Localized description"
)
}
)
}
}
},
// The API describes this member as "the content of the
// rest of the UI"
content = {
// So let's place the Scaffold here
Scaffold(
topBar = {
AppBarContent()
},
//drawerContent = { BottomBar() } // <-- Will implement a side drawer
bottomBar = {
BottomBarContent(
coroutineScope = scope,
drawerState = drawerState
)
},
) {
innerPadding ->
BodyContent( Modifier.padding( innerPadding ).fillMaxHeight() )
}
}
)
}
Here, we've leveraged the Scaffold exactly as the codelab in the compose pathway suggests we should. Notice my comment that drawerContent is an auto-implementation of the side-drawer. It's a rather nifty way to bypass directly using the [respective] Composable(s) (material design's modal drawer/sheet)! However, it won't work for our BottomDrawer. I think the API is experimental for BottomDrawer, because they'll be making changes to add support for it to Composables like Scaffold in the future.
I base that on how difficult it is to use the BottomDrawer, designed for use solely with BottomAppBar, with the Scaffold - which explicitly contains a slot for BottomAppBar.
To support BottomDrawer, we have to understand that it is an underlying layout controller that wraps the entire app's UI, preventing interaction with anything but its drawerContent when the drawer is open. This requires that it encompasses Scaffold, and that requires that we delegate necessary state control - to the BottomBarContent composable which wraps our BottomAppBar implementation:
#ExperimentalMaterialApi
#Composable
fun BottomBarContent( modifier: Modifier = Modifier, coroutineScope: CoroutineScope, drawerState: BottomDrawerState ) {
BottomAppBar{
// Leading icons should typically have a high content alpha
CompositionLocalProvider( LocalContentAlpha provides ContentAlpha.high ) {
IconButton(
onClick = {
coroutineScope.launch { drawerState.open() }
}
) {
Icon( Icons.Filled.Menu, contentDescription = "Localized description" )
}
}
// The actions should be at the end of the BottomAppBar. They use the default medium
// content alpha provided by BottomAppBar
Spacer( Modifier.weight( 1f, true ) )
IconButton( onClick = { /* doSomething() */ } ) {
Icon( Icons.Filled.Favorite, contentDescription = "Localized description" )
}
IconButton( onClick = { /* doSomething() */ } ) {
Icon( Icons.Filled.Favorite, contentDescription = "Localized description" )
}
}
}
The result shows us:
The TopAppBar at top,
The BottomAppBar at bottom,
Clicking the menu icon in the BottomAppBar opens our BottomDrawer, covering the BottomAppBar and entire content space appropriately while open.
The BottomDrawer is properly hidden, until either the above referenced button click - or gesture - is utilized to open the bottom drawer.
The menu icon in the BottomAppBar opens the drawer partway.
Gesture opens the bottom drawer partway with a quick short swipe, but as far as you guide it to otherwise.
You may have to do something as shown below..
Notice how the Scaffold is called inside the BottomDrawer().
It's confusing though how the documentation says "They (BottomDrawer) are only used with bottom app bars". It made me think I have to look for a BottomDrawer() slot inside Scaffold or that I have to call BottomDrawer() inside BottomAppBar(). In both cases, I experienced weird behaviours. This is how I worked around the issue. I hope it helps someone especially if you are attempting the code lab exercise in Module 5 of Layouts in Jetpack Compose from the Jetpack Compose course.
#ExperimentalMaterialApi
#Composable
fun MyApp() {
var selectedItem by rememberSaveable { mutableStateOf(1)}
BottomDrawer(
modifier = Modifier.background(MaterialTheme.colors.onPrimary),
drawerShape = Shapes.medium,
drawerContent = {
Column(Modifier.fillMaxWidth()) {
for(i in 1..6) {
when (i) {
1 -> Row(modifier = Modifier.clickable { }.padding(16.dp)){
Icon(imageVector = Icons.Rounded.Inbox, contentDescription = null)
Text(text = "Inbox")
}
2 -> Row(modifier = Modifier.clickable { }.padding(16.dp)){
Icon(imageVector = Icons.Rounded.Outbox, contentDescription = null)
Text(text = "Outbox")
}
3 -> Row(modifier = Modifier.clickable { }.padding(16.dp)){
Icon(imageVector = Icons.Rounded.Archive, contentDescription = null)
Text(text = "Archive")
}
}
}
}
},
gesturesEnabled = true
) {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "Learning Compose Layouts" )
},
actions = {
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Filled.Favorite, contentDescription = null)
}
}
)
},
bottomBar = { BottomAppBar(cutoutShape = CircleShape, contentPadding = PaddingValues(0.dp)) {
for (item in 1..4) {
BottomNavigationItem(
modifier = Modifier.clipToBounds(),
selected = selectedItem == item ,
onClick = { selectedItem = item },
icon = {
when (item) {
1 -> { Icon(Icons.Rounded.MusicNote, contentDescription = null) }
2 -> { Icon(Icons.Rounded.BookmarkAdd, contentDescription = null) }
3 -> { Icon(Icons.Rounded.SportsBasketball, contentDescription = null) }
4 -> { Icon(Icons.Rounded.ShoppingCart, contentDescription = null) }
}
}
)
}
}
}
) { innerPadding -> BodyContent(
Modifier
.padding(innerPadding)
.padding(8.dp))
}
}
}
I need to add a Toolbar in my Android application with a List like below. I am using Jetpack Compose to create the UI. Below is the composable function i am using for drawing the main view.
#Composable
fun HomeScreenApp() {
showPetsList(dogs = dogData)
}
You can use the TopAppBar.
The best way is to use the Scaffold. Something like:
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "TopAppBar")
},
navigationIcon = {
IconButton(onClick = { }) {
Icon(Icons.Filled.Menu,"")
}
},
backgroundColor = ....,
contentColor = ....
)
}, content = {
})
In Jetpack compose Toolbar can be easily implemented by using a Composable function called TopAppBar. You need to place TopAppBar along with your main composable function inside a column.
#Composable
fun HomeScreenApp() {
Column() {
TopAppBar(title = { Text(text = "Adopt Me") }, backgroundColor = Color.Red)
showPetsList(dogs = dogData)
}
}
The above function calls the TopAppBar inside a column followed by your main content view. The TopAppBar function takes in a Text object(Not string) as title. This can also be any Composable function. You can also specify other params like backgroundColor, navigationIcon, contentColor etc. Remember that TopAppBar is just a Composable provided by Jetpack team. It can be your custom function also just in case you need more customization.
Output