I've two components Brand and SignInCreateAccount. Each component created by ConstraintLayout. Now, I create WelcomeScreen from above components.
Usecase 1: WelcomeScreen using still ConstraintLayout (ConstraintLayout inside ConstraintLayout)
#Composable
fun WelcomeScreen(modifier: Modifier = Modifier) {
ConstraintLayout {
val (brand, formSignIn) = createRefs()
Brand(modifier = modifier.constrainAs(brand) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
SignInCreateAccount(modifier = modifier.constrainAs(formSignIn) {
start.linkTo(brand.start)
end.linkTo(brand.end)
top.linkTo(brand.bottom)
})
}
}
Result: Layout preview not show anything
Usecase 2: WelcomeScreen using Column(ConstrantLayout inside Column)
#Composable
fun WelcomeScreen(modifier: Modifier = Modifier) {
Column {
Brand()
SignInCreateAccount()
}
}
Result: Layout preview show expected result
Brand and SignInCreateAccount components
#Composable
fun SignInCreateAccount(modifier: Modifier = Modifier) {
ConstraintLayout {
val (titleSignIn, email, buttonContinue, titleOr, buttonSignGuest) = createRefs()
Text(
text = stringResource(id = R.string.sign_in_create_account),
modifier = modifier.constrainAs(titleSignIn) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
Text(text = "... Enter your mail", modifier = modifier.constrainAs(email) {
start.linkTo(titleSignIn.start)
end.linkTo(titleSignIn.end)
top.linkTo(titleSignIn.bottom)
})
}
}
#Composable
fun Brand(modifier: Modifier = Modifier) {
ConstraintLayout {
val (logo, slogan) = createRefs()
Logo(modifier = modifier.constrainAs(logo) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
Text(text = stringResource(id = R.string.app_tagline),
modifier = modifier.constrainAs(slogan) {
start.linkTo(logo.start)
end.linkTo(logo.end)
top.linkTo(logo.bottom)
})
}
}
#Composable
fun Logo(
modifier: Modifier = Modifier,
lightTheme: Boolean = MaterialTheme.colors.isLight
) {
val assetId = if (lightTheme) {
R.drawable.ic_logo_light
} else {
R.drawable.ic_logo_dark
}
Image(
painter = painterResource(id = assetId),
modifier = modifier,
contentDescription = null
)
}
I want to using ConstraintLayout(as hobby) as use case 1. But I don't know what I did wrong or is there something wrong with ConstraintLayout.
Update: I missed a modifier parameter to the inner constraint layouts. However, another problem arose. That layout rearanged correct, but it not show anything: text, image.
WelcomeScreen.kt
#Composable
fun WelcomeScreen(modifier: Modifier = Modifier) {
ConstraintLayout(modifier = modifier) {
val (brand, formSignIn) = createRefs()
Brand(modifier = modifier.constrainAs(brand) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
SignInCreateAccount(modifier = modifier.constrainAs(formSignIn) {
start.linkTo(brand.start)
end.linkTo(brand.end)
top.linkTo(brand.bottom)
})
}
}
#Composable
fun SignInCreateAccount(modifier: Modifier = Modifier) {
ConstraintLayout(modifier = modifier) {
val (titleSignIn, email, buttonContinue, titleOr, buttonSignGuest) = createRefs()
Text(
text = stringResource(id = R.string.sign_in_create_account),
modifier = modifier.constrainAs(titleSignIn) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
Text(text = "... Enter your mail", modifier = modifier.constrainAs(email) {
start.linkTo(titleSignIn.start)
end.linkTo(titleSignIn.end)
top.linkTo(titleSignIn.bottom)
})
}
}
#Composable
fun Brand(modifier: Modifier = Modifier) {
ConstraintLayout(modifier = modifier) {
val (logo, slogan) = createRefs()
Logo(modifier = modifier.constrainAs(logo) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
Text(text = stringResource(id = R.string.app_tagline),
modifier = modifier.constrainAs(slogan) {
start.linkTo(logo.start)
end.linkTo(logo.end)
top.linkTo(logo.bottom)
})
}
}
#Composable
fun Logo(
modifier: Modifier = Modifier,
lightTheme: Boolean = MaterialTheme.colors.isLight
) {
val assetId = if (lightTheme) {
R.drawable.ic_logo_light
} else {
R.drawable.ic_logo_dark
}
Image(
painter = painterResource(id = assetId),
modifier = modifier,
contentDescription = null
)
}
#Preview
#Composable
fun DevPreview() {
JetsurveyTheme(darkTheme = false) {
WelcomeScreen()
}
}
You are not passing the modifier parameter to the inner constraint layouts (ones in Brand and SignInCreateAccount), so all the constraints you set on them from the WelcomeScreen don't get passed along, and therefore not appearing on the screen.
For example your Brand composable should like something like this:
#Composable
fun Brand(modifier: Modifier = Modifier) {
ConstraintLayout(modifier = modifier) {
val (logo, slogan) = createRefs()
Logo(modifier = modifier.constrainAs(logo) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
Text(text = stringResource(id = R.string.app_tagline),
modifier = modifier.constrainAs(slogan) {
start.linkTo(logo.start)
end.linkTo(logo.end)
top.linkTo(logo.bottom)
})
}
}
And the SignInCreateAccount would look like this
#Composable
fun SignInCreateAccount(modifier: Modifier = Modifier) {
ConstraintLayout(modifier = modifier) {
val (titleSignIn, email, buttonContinue, titleOr, buttonSignGuest) = createRefs()
Text(
text = stringResource(id = R.string.sign_in_create_account),
modifier = modifier.constrainAs(titleSignIn) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top)
})
Text(text = "... Enter your mail", modifier = modifier.constrainAs(email) {
start.linkTo(titleSignIn.start)
end.linkTo(titleSignIn.end)
top.linkTo(titleSignIn.bottom)
})
}
}
Related
I am creating Heterogenous list using jetpack compose. I have an issue with recomposition when one of the item is clicked.
My Idea is to update the list with new item when an item clicked, I am receiving update list but list is not recomposed.
Please find below code:
//Initial function that prepared screen where content of list is wrapped in Scafold
#Composable fun PrepareOverViewScreen(overViewList: List<OverViewListItem>) {
val infoList = remember {mutableStateOf(overViewList) }
Scaffold(topBar = { TopBar("OverView") },
content = { DisplayOverViewScreen(overViewList = overViewList) },
backgroundColor = Color(0xFFf2f2f2)
)
}
//Displays list using LazyColumn when in itemType OverViewHeaderItem I am trying to recompose list with latest data , but not succesful.
#Composable fun DisplayOverViewScreen(
modifier: Modifier = Modifier, overViewList: List<OverViewListItem>
) {
val infoList = remember {mutableStateOf(overViewList) }
LazyColumn(modifier = modifier) {
items(infoList.value) { data ->
when (data) {
is OverViewHeaderItem -> {
HeaderItem(data,infoList.value,onClick = { newValue ->
println("New Value is $newValue")
infoList.value = newValue.toMutableList()
})
}
is OverViewChildItem -> {
ChildListBasedOnListType(data)
}
}
}
}
}
//In this function the onClick is executed when clicked on Image()
#Composable fun HeaderItem(overViewHeaderItem: OverViewHeaderItem,overViewList: List<OverViewListItem>,onClick: (List<OverViewListItem>) -> Unit) {
var angle by remember {
mutableStateOf(0f)
}
Row(modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(color = Color(0xffd7d7d7)),
horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically) {
Text(
text = stringResource(R.string.history_yesterday), color = Color.Black,
modifier = Modifier.padding(start = 16.dp)
)
// Spacer(Modifier.weight(1f))
Image(
painter = painterResource(id = R.drawable.ic_expand_more),
modifier = Modifier
.padding(end = 5.dp)
.rotate(angle)
.clickable {
angle = (angle + 180) % 360f
// canDisplayChild = ! canDisplayChild
overViewList.map {
when (it) {
is OverViewChildItem -> {
if (it.listType == ItemType.HISTORY_YESTERDAY_CHILD) {
it.canShowHistoryChild = true
}
}
else -> {}
}
}
onClick(overViewList)
},
contentDescription = "Expandable Image"
)
}
}
Please help me resolve this issue.
#Composable fun ChildListBasedOnListType(overViewChildItem: OverViewChildItem){
when(overViewChildItem.listType){
ItemType.HISTORY_YESTERDAY_CHILD -> {
if(overViewChildItem.canShowHistoryChild){
ChildListItem(overViewChildItem)
Divider(color = Color(0xffd7d7d7), thickness = 1.dp)
}
}
else -> {
ChildListItem(overViewChildItem)
Divider(color = Color(0xffd7d7d7), thickness = 1.dp)
}
}
}
#Composable fun ChildListItem(overViewChildItem: OverViewChildItem) {
ConstraintLayout(
constraintSet = getConstraints(),
modifier = Modifier
.fillMaxSize()
.height(60.dp)
.background(color = Color(0xffffffff))
) {
Text(
text = overViewChildItem.article.articleName, Modifier
.layoutId("articleLabel")
.padding(start = 16.dp)
.fillMaxWidth()
.wrapContentHeight()
)
Text(
text = overViewChildItem.article.description, Modifier
.layoutId("desc")
.padding(start = 16.dp)
.fillMaxWidth()
.wrapContentHeight()
)
Image(
painter = painterResource(id = R.drawable.ic_baseline_chevron_right_24),
modifier = Modifier.layoutId("detail"), contentDescription = "Detail Image"
)
}
}
#Composable fun getConstraints(): ConstraintSet {
return ConstraintSet {
val articleLabel = createRefFor("articleLabel")
val articleDesc = createRefFor("desc")
val detailImage = createRefFor("detail")
createVerticalChain(articleLabel, articleDesc, chainStyle = ChainStyle.Packed)
constrain(articleLabel) {
top.linkTo(parent.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
constrain(articleDesc) {
top.linkTo(articleLabel.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
constrain(detailImage){
top.linkTo(parent.top)
end.linkTo(parent.end,5.dp)
bottom.linkTo(parent.bottom)
}
}
}
I am new to Compose and I would like to make a design like below.
The problem I am facing is when I set offset (y=-100) it is adjusting the start of the height but after the widget is moved I can still see the empty space. So it is not reflecting the widget's actual measurements.
Check below layout hierarchy snippets. I am using offset in the Card modifier.
Surface(){
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
HorizontalPager() {
...................
Image(
painterResource(currentImage.value),
contentScale = ContentScale.Fit,
modifier = Modifier.fillMaxWidth()
)
}
}
Card(
modifier = Modifier.offset(0.dp, (-100).dp)
.fillMaxWidth()
.padding(horizontal = 24.dp)
) {
Column {
.......
}
}
Spacer(modifier = Modifier.padding(16.dp))
LazyRow(modifier = Modifier.padding(start = 8.dp, bottom = 16.dp)) {
items(10) {
Card {
Column(modifier = Modifier.padding(16.dp)) {
..........
}
}
Spacer(modifier = Modifier.width(8.dp))
}
}
}
}
I learn the Constraint layout quickly and figured out how I can apply guidelines in compose.
It is easy to apply constraints in a Constraint Layout. For those of you who don't know how to implement constraint layout, I am giving you a quick guide.
Create Constraint Layout
ConstraintLayout() {
...... Add your widgets here
}
Define Constraint references & GuideLine within the constraint layout
val startGuideline = createGuidelineFromTop(0.25f)
val (viewPager, accountList, spacer, insightCards) = createRefs()
Apply constraints using Modifier.constrainAs()
Modifier.constrainAs(accountList) {
start.linkTo(parent.start)
top.linkTo(startGuideline)
}
In My case, I need four constraints so I just declare four references and provide constraints to those.
Here is the complete snippet of my compose layout
#OptIn(ExperimentalPagerApi::class)
#Composable
fun MyApp() {
val imageList = listOf(R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e, R.drawable.f)
val pagerState = rememberPagerState()
val currentImage = remember(pagerState) { mutableStateOf(R.drawable.a) }
val scroll = rememberScrollState()
Surface(
modifier = Modifier
.fillMaxSize(),
color = Color(0xFF546E7A)
) {
ConstraintLayout(modifier = Modifier.verticalScroll(scroll)) {
// Create guideline from the top of the parent at 20% the height of the Composable
val startGuideline = createGuidelineFromTop(0.2f)
val (viewPager, accountList, spacer, insightCards) = createRefs()
HorizontalPager(
modifier = Modifier
.constrainAs(viewPager) {
start.linkTo(parent.start)
top.linkTo(parent.top)
},
count = imageList.size, state = pagerState
) { page ->
when (page) {
0 -> currentImage.value = imageList[0]
1 -> currentImage.value = imageList[1]
2 -> currentImage.value = imageList[2]
3 -> currentImage.value = imageList[3]
4 -> currentImage.value = imageList[4]
5 -> currentImage.value = imageList[5]
else -> currentImage.value = R.drawable.a
}
Image(
painterResource(currentImage.value),
contentScale = ContentScale.FillBounds,
contentDescription = "",
modifier = Modifier.fillMaxWidth()
)
}
Card(
modifier = Modifier
.constrainAs(accountList) {
start.linkTo(parent.start)
top.linkTo(startGuideline)
}
.fillMaxWidth()
.padding(horizontal = 28.dp), elevation = 12.dp
) {
Column {
for (i in 1..15)
Text(text = "Account $i", modifier = Modifier.padding(16.dp))
}
}
Spacer(modifier = Modifier
.constrainAs(spacer) {
start.linkTo(parent.start)
top.linkTo(accountList.bottom)
}
.padding(16.dp))
LazyRow(modifier = Modifier
.constrainAs(insightCards) {
start.linkTo(parent.start)
top.linkTo(spacer.bottom)
}
.padding(start = 8.dp, bottom = 16.dp)
) {
items(10) {
Card {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = "Jetpack")
Spacer(modifier = Modifier.height(8.dp))
Text(text = "Compose")
}
}
Spacer(modifier = Modifier.width(8.dp))
}
}
}
}
}
I have a custom search bar will not allow me to place a cursor and type text into it. Before adding the viewmodel and state, I was able to have the TextField work and allow typing text into it.
I've tried using state variables within the composable instead of separating the logic into the view model and unfortunatly recieved the same result. I have a feeling it's something simple that I'm missing but can't quite find it.
Custom Search Bar:
#Composable
fun SearchBar(
modifier: Modifier,
viewModel: ToolSetListViewModel = hiltViewModel()
){
Surface (
modifier = modifier
.fillMaxWidth()
.height(74.dp)
.padding(20.dp, 15.dp, 20.dp, 0.dp),
elevation = 10.dp,
color = MaterialTheme.colors.primary,
shape = RoundedCornerShape(25)
){
TextField(
modifier = modifier
.fillMaxWidth(),
value = viewModel.searchText,
onValueChange = {
viewModel.onEvent(ToolSetListEvent.OnSearchToolSet(it))
},
placeholder = {
Text(
modifier = modifier
.alpha(ContentAlpha.medium),
text = "Search...",
color = White
)
},
textStyle = TextStyle(
fontSize = MaterialTheme.typography.subtitle1.fontSize,
),
singleLine = true,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
cursorColor = White
)
)
}
Screen:
#Composable
fun ToolSetListScreen(
onNavigate: (UiEvent.Navigate) -> Unit,
viewModel: ToolSetListViewModel = hiltViewModel()
) {
val toolSets = viewModel.toolSets.collectAsState(initial = emptyList())
LaunchedEffect(key1 = true) {
viewModel.uiEvent.collect { event ->
when(event) {
is UiEvent.Navigate -> onNavigate(event)
}
}
}
Scaffold (
floatingActionButton = {
FloatingActionButton(onClick = {
viewModel.onEvent(ToolSetListEvent.OnAddToolSetClick)
}) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Add")
}
}
) {
SearchBar(
modifier = Modifier,
)
LazyColumn(
modifier = Modifier.fillMaxSize()
.padding(0.dp, 20.dp)
) {
items(toolSets.value) { toolset ->
ToolSetItem(
toolSet = toolset,
onEvent = viewModel::onEvent,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
viewModel.onEvent(ToolSetListEvent.OnToolSetClick(toolset))
}
)
}
}
}
}
ViewModel:
#HiltViewModel
class ToolSetListViewModel #Inject constructor(
private val repository: ToolSetRepository
): ViewModel() {
val toolSets = repository.getAllToolSets()
private val _uiEvent = Channel<UiEvent>()
val uiEvent = _uiEvent.receiveAsFlow()
var searchText by mutableStateOf("")
private set
fun onEvent(event: ToolSetListEvent) {
when(event) {
is ToolSetListEvent.OnToolSetClick -> {
sendUiEvent(UiEvent.Navigate(Routes.ADD_EDIT_TOOL_SET + "?PONumber=${event.toolSet.PONumber}"))
}
is ToolSetListEvent.OnDeleteToolSetClick -> {
viewModelScope.launch {
repository.deleteToolSet(event.toolset)
}
}
is ToolSetListEvent.OnAddToolSetClick -> {
sendUiEvent(UiEvent.Navigate(Routes.ADD_EDIT_TOOL_SET))
}
is ToolSetListEvent.OnSearchToolSet -> {
viewModelScope.launch {
if (event.searchText.isNotBlank()) {
searchText = event.searchText
repository.getToolSetByPO(event.searchText)
}
}
}
}
}
private fun sendUiEvent(event: UiEvent) {
viewModelScope.launch {
_uiEvent.send(event)
}
}
MainActivity:
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PunchesManagerTheme {
val navController = rememberNavController()
Scaffold (
content = {
Navigation(navController)
},
bottomBar = { BottomNavigationBar(navController = navController) },
)
}
}
}
}
#Composable
fun BottomNavigationBar(navController: NavHostController) {
BottomNavigation {
val backStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = backStackEntry?.destination?.route
NavBarItems.bottomNavItem.forEach { navItem ->
BottomNavigationItem(selected = currentRoute == navItem.route, onClick = {
navController.navigate(navItem.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = false
}
launchSingleTop = true
restoreState = true
}
},
icon = {
Icon(imageVector = navItem.icon,
contentDescription = navItem.name)
},
label = {
Text(text = navItem.name)
},
)
}
}
}
Any suggestions on what the issue may be?
I think I found the fix!
I adjusted the layout of my scaffoled in my ToolSetListScreen:
Scaffold (
content = {
SearchBar(
modifier = Modifier,
)
LazyColumn(
modifier = Modifier.fillMaxSize()
.padding(0.dp, 75.dp)
) {
items(toolSets.value) { toolset ->
ToolSetItem(
toolSet = toolset,
onEvent = viewModel::onEvent,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
viewModel.onEvent(ToolSetListEvent.OnToolSetClick(toolset))
}
)
}
}
},
floatingActionButton = {
FloatingActionButton(onClick = {
viewModel.onEvent(ToolSetListEvent.OnAddToolSetClick)
}) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Add")
}
}
)
}
and this seemed to work.
I was developing an App where I'm using Jetpack Compose as UI Design kit-tool, and as I'm quite begginer on this, I would like to know how make use of the #Preview annotation which allow to check your component visually.
I have this component:
#Composable
fun PokemonListScreen(
navController: NavController,
viewModel: PokemonListViewModel = hiltNavGraphViewModel()
) {
Surface(
color = MaterialTheme.colors.background,
modifier = Modifier.fillMaxSize()
)
{
Column {
Spacer(modifier = Modifier.height(20.dp))
Image(
painter = painterResource(id = R.drawable.ic_international_pok_mon_logo),
contentDescription = "Pokemon",
modifier = Modifier
.fillMaxWidth()
.align(CenterHorizontally)
)
SearchBar(
hint = "Search...",
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
viewModel.searchPokemonList(it)
}
Spacer(modifier = Modifier.height(16.dp))
PokemonList(navController = navController)
}
}
}
#Composable
fun SearchBar(
modifier: Modifier = Modifier,
hint: String = " ",
onSearch: (String) -> Unit = { }
) {
var text by remember {
mutableStateOf("")
}
var isHintDisplayed by remember {
mutableStateOf(hint != "")
}
Box(modifier = modifier) {
BasicTextField(value = text,
onValueChange = {
text = it
onSearch(it)
},
maxLines = 1,
singleLine = true,
textStyle = TextStyle(color = Color.Black),
modifier = Modifier
.fillMaxWidth()
.shadow(5.dp, CircleShape)
.background(Color.White, CircleShape)
.padding(horizontal = 20.dp, vertical = 12.dp)
.onFocusChanged {
// isHintDisplayed = it != FocusState.Active && text.isEmpty()
}
)
if (isHintDisplayed) {
Text(
text = hint,
color = Color.LightGray,
modifier = Modifier
.padding(horizontal = 20.dp, vertical = 12.dp)
)
}
}
}
#Composable
fun PokemonList(
navController: NavController,
viewModel: PokemonListViewModel = hiltViewModel()
) {
val pokemonList by remember { viewModel.pokemonList }
val endReached by remember { viewModel.endReached }
val loadError by remember { viewModel.loadError }
val isLoading by remember { viewModel.isLoading }
val isSearching by remember { viewModel.isSearching }
LazyColumn(contentPadding = PaddingValues(16.dp)) {
val itemCount = if (pokemonList.size % 2 == 0) {
pokemonList.size / 2
} else {
pokemonList.size / 2 + 1
}
items(itemCount) {
if (it >= itemCount - 1 && !endReached && !isLoading && !isSearching) {
viewModel.loadPokemonPaginated()
}
PokedexRow(rowIndex = it, entries = pokemonList, navController = navController)
}
}
Box(
contentAlignment = Center,
modifier = Modifier.fillMaxSize()
) {
if (isLoading) {
CircularProgressIndicator(color = MaterialTheme.colors.primary)
}
if (loadError.isNotEmpty()) {
RetrySection(error = loadError) {
viewModel.loadPokemonPaginated()
}
}
}
}
I try to do something like this:
#Preview
#Composable
fun previewPokemonListScreen(){
PokemonListScreen(
navController = rememberNavController(),
viewModel = hiltNavGraphViewModel())
}
But I'm getting the following error:
Delete access not allowed during rendering (C:\Users\manuel.lucas\AndroidStudioProjects\JetpackComposePokedex\.gradle\build-attribution\androidGradlePluginAttributionData)
So how should I initialized my #Preview component. I have to pass some extra argument than the original componenent doesn't have.
Thanks in advance for the help!
Try to do like this
#Preview(showBackground = true)
#Composable
fun PreviewPokemonListScreen() {
YourThemeAppName {
PokemonListScreen(
navController = rememberNavController(), //Remove the view model
)
}
}
I am try to learning jetpack compose those days, so I want to learning bottom sheet in jetpack compose, I do it just for one text, but I want to use it for multiple text, I have one example here, but I am not sure how to implement to my project, is there any solution for more than two text button to apply bottom sheet?
#Composable
fun BottomSheetMyScreen() {
val modalBottomSheetState = rememberModalBottomSheetState(initialValue =
ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetContent = {
BottomSheetFirstScreen()
},
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 5.dp, topEnd = 5.dp),
sheetBackgroundColor = Color.Red,
) {
Scaffold(
backgroundColor = Color.Red
) {
MyScreen(
scope = scope, state = modalBottomSheetState
)}}}
#Composable
fun MyScreen(
scope: CoroutineScope, state: ModalBottomSheetState,
) {
MainRow(
name = "name1",
onClick = { scope.launch {
state.show()
}}
)
MainRow(
name = "name2",
onClick = { scope.launch {
state.show()
} }
)}}
#Composable
fun MainRow(
name: String,
onClick: () -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.clickable(onClick = onClick),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.width(150.dp)
) {
Text(
text = name,
)}}}
I edit Your Code, you can use this code:
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun BottomSheetMyScreen() {
val modalBottomSheetState = rememberModalBottomSheetState(
initialValue =
ModalBottomSheetValue.Hidden
)
val scope = rememberCoroutineScope()
val sheetContentState = remember {
mutableStateOf(0)
}
ModalBottomSheetLayout(
sheetContent = {
when (sheetContentState.value) {
0 -> {
BottomSheetFirstScreen()
}
1 -> {
BottomSheetSecondScreen()
}
}
},
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 5.dp, topEnd = 5.dp),
sheetBackgroundColor = Color.Red,
) {
Scaffold(
backgroundColor = Color.Red
) {
MyScreen(
scope = scope, state = modalBottomSheetState, sheetContentState = sheetContentState
)
}
}
}
Main Row
#Composable
fun MainRow(
name: String,
onClick: () -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = name,
modifier = Modifier.clickable { onClick.invoke() }
)
}
}
And MyScreen
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun MyScreen(
scope: CoroutineScope,
state: ModalBottomSheetState,
sheetContentState: MutableState<Int>
) {
Column(modifier = Modifier.fillMaxWidth()) {
MainRow(
name = "name 1",
onClick = {
scope.launch {
sheetContentState.value = 0
state.show()
}
}
)
MainRow(
name = "name 2",
onClick = {
scope.launch {
sheetContentState.value = 1
state.show()
}
}
)
}
}