I implemented a navigation drawer using jetpack compose. It looks like this
But it's not like the usual navigation drawer. it's not covering the status bar. I want this status bar like that one
here is my model navigation drawer code
#Composable
fun Drawer(scope: CoroutineScope, scaffoldState: ScaffoldState, navController: NavController) {
val items = listOf(
NavDrawerItem.Home,
NavDrawerItem.Music,
NavDrawerItem.Movies,
NavDrawerItem.Books,
NavDrawerItem.Profile,
NavDrawerItem.Settings
)
val item1 = "Logout"
Column(
modifier = Modifier
.background(colorResource(id = R.color.white))
.fillMaxSize()
) {
Image(
painter = painterResource(id = R.drawable.logo1),
contentDescription = R.drawable.logo1.toString(),
modifier = Modifier
.height(100.dp)
.fillMaxWidth()
.padding(10.dp)
)
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(5.dp)
)
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
items.forEach { item ->
DrawerItem(item = item, selected = currentRoute == item.route, onItemClick = {
navController.navigate(item.route) {
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) {
saveState = true
}
}
launchSingleTop = true
restoreState = true
}
scope.launch {
scaffoldState.drawerState.close()
}
})
}
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(5.dp)
)
Logout(scope, scaffoldState)
Spacer(modifier = Modifier.weight(1f))
Text(
text = "Developed by CrazyBot Studio",
color = Color.Black,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(12.dp)
.align(Alignment.CenterHorizontally)
)
}
}
Is this possible on jetpack compose if yes the how can I do that?
You can check the Jetnews code:
In your Activity you can use something like:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
YourComposeTheme {
ProvideWindowInsets {
val systemUiController = rememberSystemUiController()
val darkIcons = MaterialTheme.colors.isLight
SideEffect {
systemUiController.setSystemBarsColor(Color.Transparent, darkIcons = darkIcons)
}
//SimpleScaffoldWithTopBar()
//Your Scaffold or Drawer code
}
}
}
Please try the below code in your Activity file.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
makeStatusBarTransparent()
}
private fun makeStatusBarTransparent() {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
I hope it works for you!!!
Related
Let say i have a two screen;
#Composable
fun Screen1(
toScreen2:() -> Unit
) {
Box(
modifier = Modifier.fillMaxSize().border(4.dp, Color.Gray),
contentAlignment = Alignment.Center
) {
Text(text = "Screen 1")
Button(onClick = { toScreen2() }) {
Text(text = "To Screen 2")
}
}
}
#Composable
fun Screen2(
toScreen1:() -> Unit
) {
Box(
modifier = Modifier.fillMaxSize().border(4.dp, Color.Gray),
contentAlignment = Alignment.Center
) {
Text(text = "Screen 2")
Button(onClick = { toScreen1() }) {
Text(text = "To Screen 1")
}
}
}
and top bar that I can control the visibility;
#Composable
fun MyTopBar(
currentRoute: String?
) {
val isVisible = currentRoute == "Screen1"
AnimatedVisibility(
visible = isVisible,
enter = fadeIn(),
exit = fadeOut()
) {
TopAppBar(backgroundColor = Color.Red){}
}
}
Sccafold
val scaffoldState = rememberScaffoldState()
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
Scaffold(
modifier = Modifier
.fillMaxSize(),
scaffoldState = scaffoldState,
topBar = { MyTopBar(currentRoute) },
backgroundColor = Color.White
){
NavHost(
navController = navController,
startDestination = "Screen1"
){
composable("Screen1"){
Screen1(toScreen2 = { navController.navigate("Screen2") })
}
composable("Screen2"){
Screen2(toScreen1 = { navController.navigate("Screen1") })
}
}
}
How can i prevent this delayed effect;
i want to instant efect that simultaneously with the disappearance speed of the bottom bar. You can see that the border of the screen lags behind the topbar disappearance speed.
Remove the AnimatedVisibility from the MyTopBar.
You have animations for the TopBar visibility. So it won't be instantaneous.
I have created a Pokemon App with Jetpack Compose. I have two screens. One where the names of the pokemon is being displayed, and a second screen where the details of a selected pokemon will be shown. What I want to achieve is passing the name of the pokemon to a url when it's selected, and getting the information on to the second screen.
const val POKE_DETAILS = "api/v2/pokemon/{name}/"
Network File
interface NetworkingService{
#GET(Endpoints.POKE_LIST)
suspend fun getListResponse(
#Query("limit") limit: String = "151"
): Response<GetPokemonListResponse>
#GET(Endpoints.POKE_DETAILS)
suspend fun getDetailsResponse(
#Path("name") name: String
): GetPokemonDetailResponse
}
object PokemonNetworkObject{
val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()
val retroFit: Retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
val networkingServices: NetworkingService by lazy {
retroFit.create(NetworkingService::class.java)
}
val apiClient = ApiClient(networkingServices)
}
Compose Screens
#Preview
#Composable
fun PokemonListPage(pokemonViewModel: PokemonListViewModel = viewModel(), navController: NavController){
val pokeList = pokemonViewModel.pokemonStateData.collectAsState().value
Surface(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(),
) {
Scaffold(topBar =
{
TopAppBar(
backgroundColor = Color.DarkGray,
elevation = 0.dp,
) {
Row(modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
){
Text(
text = "POKEDEX",
fontWeight = FontWeight.Bold,
fontSize = 25.sp,
color = Color.Magenta
)
}
}
}, backgroundColor = Color.DarkGray){
PokemonCards(pokemons = pokeList!!, navController = navController))
}
// PokemonCards(pokemons = pokeList!!)
}
}
#Composable
private fun PokemonCards(pokemons: List<PokeListEntity>, navController: NavController) {
LazyColumn{
items(pokemons){ pokemon ->
PokemonCard(pokemon = pokemon, navController = navController)
}
}
}
#Composable
private fun PokemonCard(pokemon: PokeListEntity, navController: NavController) {
Card(
modifier = Modifier
.width(500.dp)
.requiredHeight(100.dp)
.padding(10.dp),
backgroundColor = Color.Cyan,
shape = RoundedCornerShape(corner = CornerSize(10.dp)),
elevation = 5.dp
) {
Row(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = pokemon.name,
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
Button(
onClick = {
navController.navigate(route = "pokemon_detail_screen/${pokemon.name}")
}) {
Text(text = "INFO")
}
}
}
}
Details Screen
#Preview
#Composable
fun PokemonDetailScreen(
detailViewModel: DetailViewModel = viewModel(),
navController: NavController,
pokemonName: String // This Variable
) {
val details by detailViewModel.detailState.observeAsState()
Surface(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
color = Color.DarkGray
) {
DetailCard(field = details!!)
}
}
#Composable
private fun DetailCard(field: GetPokemonDetailResponse) {
Card(
modifier = Modifier
.requiredHeight(300.dp)
.fillMaxWidth()
.padding(10.dp),
backgroundColor = Color.Cyan,
shape = RoundedCornerShape(corner = CornerSize(15.dp)),
elevation = 10.dp
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.padding(10.dp),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
DetailFields("Name:", field = field.name)
Divider(thickness = 4.dp)
DetailFields("Height:", field = "${field.height}.in")
Divider(thickness = 4.dp)
DetailFields("Weight:", field = "${field.weight}.lbs")
}
}
}
#Composable
private fun DetailFields(title: String, field: String) {
Column() {
Text(
title,
fontSize = 20.sp
)
Text(
field,
fontSize = 30.sp,
fontWeight = FontWeight.Bold
)
}
}
MainActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PokeDexComposeTheme {
Surface(
modifier = Modifier.fillMaxSize()
) {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "pokemon_list_page"
) {
composable("pokemon_list_page") {
PokemonListPage(navController = navController)
}
composable(
"pokemon_detail_screen/{name}",
arguments = listOf(
navArgument("name") {
type = NavType.StringType
}
)
) {
// The navBackStackEntry contains the arguments
val pokemonName = remember {
it.arguments?.getString("name")
}
PokemonDetailScreen(
pokemonName = pokemonName?.lowercase() ?: "",
navController = navController)
}
}
// val pokeListViewModel = viewModel<PokemonListViewModel>()
// PokemonListPage(pokeListViewModel)
}
}
}
}
}
This is still pretty new to me. Any Suggestions are definitely welcomed. Thanks.
Update
I have created a Navigation Component, but i don't know where to pass the pokemonName String value in the Details Screen
*Here is a copy of the project, if you want to test some things out.
https://drive.google.com/drive/folders/1gLH_Q3jYLhn-6ad0LMBeZHb8HyT8FszC?usp=sharing
I am try to learn jetpack compose, and I want to apply bottom sheet for on long click listener, I have example of code below, and I try to use bottom sheet for onLongClick listener, but I have some confused about how can I apply for row data? I had some example but I do not have an idea about this problem?
#Composable
fun BSDataScreen() {
val modalBottomSheetState = rememberModalBottomSheetState(initialValue =
ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetContent = {
SheetScreen()
},
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 15.dp, topEnd = 15.dp),
sheetBackgroundColor = Color.White,
) {
Scaffold(
backgroundColor = Color.White,
) {
DataScreen(
scope = scope, state = modalBottomSheetState)}}}
#Composable
fun DataScreen(
scope: CoroutineScope,
state: ModalBottomSheetState
) {
val listOfData = listOf(
Data( painterResource(R.drawable.image1)),
Data(painterResource(R.drawable.image2)),
Data(painterResource(R.drawable.image3),)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
LazyColumn(
modifier = Modifier
) {
items(listOfData.size) { index ->
DataListItem(listOfData[index])}}}}
#Composable
fun DataListItem(data: Data) {
val context = LocalContext.current
Column(
modifier = Modifier.padding(5.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.combinedClickable(
onLongClick= {
scope.launch {
state.show()
}},)
) {
Image(
painter = data.painter,
contentDescription = null,)}}}
You can create a lambda onClick: (Data) -> Unit and hoist state from DataListItem to DataScreen for each item
#Composable
fun DataListItem(data: Data, onLongClick: (Data) -> Unit) {
val context = LocalContext.current
Column(
modifier = Modifier.padding(5.dp)
) {
Row(modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.combinedClickable(
onClick = {
},
onLongClick = {
onLongClick(data)
}
)
) {
}
}
}
And in DataScreen
LazyColumn(
modifier = Modifier
) {
items(listOfData.size) { index ->
DataListItem(listOfData[index]) { data: Data->
// you can call bottom sheet or pass data if required
scope.launch {
state.show()
}
}
}
}
I try to learn jetpack compose these days, and I have a simple project in jetpack compose, bottom sheet work in my project, but when I use bottom navigation, it is not work, I search in many website and stackoverflow especially, but I did not find any solution, I do not know what I missed? is there any idea?
#Composable
fun BSDataScreen() {
val modalBottomSheetState = rememberModalBottomSheetState(initialValue =
ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetContent = {
SheetScreen()
},
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 15.dp, topEnd = 15.dp),
sheetBackgroundColor = Color.White,
) {
Scaffold(
backgroundColor = Color.White,
) {
DataScreen(
scope = scope, state = modalBottomSheetState)}}}
#Composable
fun DataScreen(
scope: CoroutineScope,
state: ModalBottomSheetState
) {
val listOfData = listOf(
Data( painterResource(R.drawable.image1)),
Data(painterResource(R.drawable.image2)),
Data(painterResource(R.drawable.image3),)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
LazyColumn(
modifier = Modifier
) {
items(listOfData.size) { index ->
DataListItem(listOfData[index]) data: Data->
scope.launch {
state.show()
}
}}}}
#Composable
fun DataListItem(data: Data, onLongClick: (Data) -> Unit) {
val context = LocalContext.current
Column(
modifier = Modifier.padding(5.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.combinedClickable(
onLongClick= {
onLongClick(data)
},)
) {
Image(
painter = data.painter,
contentDescription = null,)}}}
BottomNav:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MainScreen()
}
}
}
#Composable
fun MainScreen() {
val navController = rememberNavController()
Scaffold(
bottomBar = { BottomNavigationBar(navController) }
) {
Navigation(navController = navController)
}
}
#Composable
fun Navigation(navController: NavHostController) {
val modalBottomSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
NavHost(navController, startDestination = NavigationItem.Data.route) {
composable(NavigationItem.Data.route) {
DataScreen(
scope = scope, state = modalBottomSheetState
)
}
composable(NavigationItem.Data2.route) {
Data2Screen()
}
composable(NavigationItem.Data3.route) {
Data3Screen()
}
composable(NavigationItem.Data4.route) {
Data4Screen()
}
composable(NavigationItem.Data5.route) {
Data5Screen()
}
}
}
#Composable
fun BottomNavigationBar(navController: NavController
) {
val items = listOf(
NavigationItem.Data,
NavigationItem.Data2,
NavigationItem.Data3,
NavigationItem.Data4,
NavigationItem.Data5
)
BottomNavigation(
backgroundColor = colorResource(id = R.color.white),
contentColor = colorResource(id = R.color.black)
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
items.forEach { item ->
BottomNavigationItem(
icon = {
Icon(
painterResource(id = item.icon),
contentDescription = null
)
},
selectedContentColor = colorResource(id = R.color.red),
unselectedContentColor = colorResource(id = R.color.blue),
alwaysShowLabel = true,
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) {
saveState = true
}
}
launchSingleTop = true
restoreState = true
}})}}}
I think your problem is your bottom sheets appear under bottom bar. The same thing I solved is very simple.
#Composable
fun SettingView() {
val navController = rememberNavController()
val scaffoldState = rememberScaffoldState()
Scaffold(
bottomBar = {
BottomBar(navController = navController)
},
content = {
Box(modifier = Modifier.padding(it)) {
BottomNavGraph(
navController = navController,
scaffoldState = scaffoldState
)
}
}
)
}
content screens wrap with Box and padding to scaffold's PaddingValues.
Just wrap the whole screen with ModalBottomSheetLayout.
You can put the following code:
Scaffold(
bottomBar = { BottomNavigationBar(navController) }
) {
Navigation(navController = navController)
}
inside
ModalBottomSheetLayout(...){
Scaffold(
bottomBar = { BottomNavigationBar(navController) }
) {
Navigation(navController = navController)
}
}
Try using the Navigation Material library provided by Accompanist.
https://google.github.io/accompanist/navigation-material/
I am start to migrate my project to jetpack compose, and I am learning jetpack compose now, I want to use bottom sheet in my project, I search on internet to use bottom sheet, I find some codes, I use it in my app, every things looks good, but when I run the my app, it crashed, I am not sure where I mistake? Is there any other solution?
class MyActivity : ComponentActivity() {
#ExperimentalMaterialApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ModalBottomSheetLayoutScreen()
}
}
}
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun ModalBottomSheetLayoutScreen() {
val modalBottomSheetState = rememberModalBottomSheetState(initialValue =
ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetContent = {
},
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
sheetBackgroundColor = colorResource(id = R.color.white),
// scrimColor = Color.Red, // Color for the fade background when you open/close the drawer
) {
Scaffold(
backgroundColor = colorResource(id = R.color.white)
) {
MyScreen(scope = scope, state = modalBottomSheetState)
}
}
}
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun MyScreen(
scope: CoroutineScope, state: ModalBottomSheetState
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
modifier = Modifier
.width(170.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "click",
modifier = Modifier
.clickable {
scope.launch {
state.show()
}
}
)}} }
#Preview(showBackground = true)
#Composable
fun ModalBottomSheetLayoutScreenPreview() {
ModalBottomSheetLayoutScreen()
}
It crashes because your sheetContent is empty. I've reported this bug. In a real app you should have some content, otherwise you don't need ModalBottomSheetLayout at all.
Specifying any view inside sheetContent solves the problem.