I want to create this type of slid switch using jetpack compose but I don't know how to do it can anyone help me with it? it will toggle between this 2 option
You can use TabRow like this:
val items = (0..1)
var activeTabIndex by remember { mutableStateOf(0) }
TabRow(
selectedTabIndex = activeTabIndex, backgroundColor = Color.Transparent,
indicator = {
Box(
Modifier
.tabIndicatorOffset(it[activeTabIndex])
.fillMaxSize()
.background(color = Color.Cyan)
.zIndex(-1F)
)
},
) {
items.mapIndexed { i, item ->
Tab(selected = activeTabIndex == i, onClick = { activeTabIndex = i }) {
Icon(
painter = painterResource(id = someIcon),
contentDescription = null,
tint = Color.Black,
modifier = Modifier.padding(vertical = 20.dp)
)
}
}
}
Related
I have a composable of snackbar. Below is the code
#Composable
fun CealSnackbar(title: String,performAction: () -> Unit,) {
val counterState = remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
while(true) {
delay(4000)
counterState.value = false
performAction()
}
}
AnimatedVisibility(
visible = counterState.value,
enter = slideInVertically() + fadeIn(),
exit = slideOutVertically() + fadeOut(),
) {
Card(
modifier = Modifier
.absoluteOffset(x = 0.dp, y = 10.dp)
.padding(horizontal = 20.dp)
.fillMaxWidth()
.statusBarsPadding()
.background(
color = MaterialTheme.colors.primaryVariant,
shape = RoundedCornerShape(10.dp)
), elevation = 20.dp
) {
Row(
modifier = Modifier
.background(color = MaterialTheme.colors.primaryVariant)
.padding(12.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.error_circle),
contentDescription = title
)
Text(
text = title,
fontFamily = FontFamily(Font(R.font.inter_medium)),
fontSize = 12.sp,
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
}
}
I want the animation when the snackbar appears and disappears and it should be usable in any component
So while using this in other composable I am trying to display it when there is an error msg, the error msg is a state flow
if(errorMsg.isNotEmpty()){
CealSnackbar(
title = errorMsg, performAction = {
registrationViewModel.setErrorMsg("")
}
)
}
If I use it like above the animation does not take place, how should I refactor it so that I use it any composable when there is an error msg
Use SnackbarHost
val snackState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()
SnackbarHost(
hostState = snackState
){
CealSnackbar(
title = errorMsg, performAction = {
registrationViewModel.setErrorMsg("")
}
)
}
i´m new in Compose and i´m trying to manage the visibility of the TopBar when i´m scrolling a list ( LazyColumn ). I´m not pretend to use the Scaffold with Material 3 because I want to learn a bit more about Compose and Animation.
So, first of all, this is my code and it works just fine ->
#Composable
fun FavouriteCompose(stateUi: FavouriteStateUi.ShowMovies) {
Box(Modifier.fillMaxSize()) {
val state = rememberLazyListState()
val firstVisible = remember { derivedStateOf { state.firstVisibleItemIndex } }
Column(
Modifier
.fillMaxSize()
.background(color = GreenB)
) {
AnimatedVisibility(visible = firstVisible.value == 0) {
Spacer(modifier = Modifier.height(20.dp))
Paragraphs.Paragraph(
modifier = Modifier.padding(10.dp),
stringRes = R.string.favourite,
color = Color.White,
paragraphSize = Paragraphs.ParagraphSize.PARAGRAPH_24_SP
)
Spacer(modifier = Modifier.height(20.dp))
}
if (stateUi.movies?.isEmpty() == true) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(top = 10.dp)
.fillMaxSize()
.clip(RoundedCornerShape(10.dp))
.background(Color.White),
) {
Image(
alignment = Alignment.Center,
modifier = Modifier.size(200.dp),
painter = painterResource(
id = R.drawable.ic_baseline_local_movies_24
),
contentDescription = ""
)
Paragraphs.Paragraph(
modifier = Modifier
.padding(top = 10.dp)
.align(Alignment.CenterHorizontally),
stringRes = R.string.add_more_movies,
paragraphSize = Paragraphs.ParagraphSize.PARAGRAPH_24_SP
)
}
} else {
LazyColumn(
state = state,
modifier = Modifier
.fillMaxSize()
.clip(RoundedCornerShape(10.dp))
.background(Color.White)
.padding(10.dp)
) {
items(
items = stateUi.movies.orEmpty(),
key = { cardModel -> cardModel.id }
) { item -> MovieCard(item) }
}
}
}
val snackBarModel = stateUi.snackBarModel
if (snackBarModel.addOrRemoveMovie == true) {
Box(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(bottom = 10.dp)
) {
SnackBar(
stringRes = R.string.pelicula_removida,
icon = R.drawable.ic_baseline_local_movies_24,
backgroundColor = Color.Black,
textColor = LightGrey,
iconColor = Blue,
snackBarModel = snackBarModel
)
}
}
}
}
Each Time i swipe the list the topApp hides and viceversa, but i´m not sure if this is the best way to do this ( without using Scaffold with Material 3 ).
I´m creating more recompositons with this kind of solution ?, should I save the lazy state in a viewModel instead?
Thanks!.
I have lazy list and a floating action button in the bottom end, the FAB has a color. But the floating action button in jetpack compose is showing the list in the background even thought it has a color. Even after adding the elevation it is not working. How to solve it?
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
) {
androidx.compose.material3.FloatingActionButton(
containerColor = appColors.primary,
contentColor = appColors.primary,
elevation = FloatingActionButtonDefaults.elevation(8.dp),
shape = CircleShape,
onClick = {},
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp),
) {
Icon(Icons.Filled.Add, null, tint = Color.White)
}
if (viewModel.state.value.patientsList.isEmpty()) {
Text(
text = "No Patients Available",
style = FontLibrary.regularBody16(textAlign = TextAlign.Center)
)
} else {
LazyColumn(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp)
.fillMaxSize()
) {
items(
items = viewModel.state.value.patientsList,
key = { patient ->
patient.id
}
) { patient ->
PatientCard(patient)
Divider(color = appColors.secondary, thickness = 1.dp)
}
}
}
}
In Jetpack compose UI components are placed in the order as you place them, so in box you have first placed Floating action button, and then the list.
You should place FAB in the end, i.e., move its code to the bottom.
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
) {
if (viewModel.state.value.patientsList.isEmpty()) {
Text(
text = "No Patients Available",
style = FontLibrary.regularBody16(textAlign = TextAlign.Center)
)
} else {
LazyColumn(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp)
.fillMaxSize()
) {
items(
items = viewModel.state.value.patientsList,
key = { patient ->
patient.id
}
) { patient ->
PatientCard(patient)
Divider(color = appColors.secondary, thickness = 1.dp)
}
}
}
androidx.compose.material3.FloatingActionButton(
containerColor = appColors.primary,
contentColor = appColors.primary,
shape = CircleShape,
onClick = {},
modifier = Modifier
.align(BottomEnd)
.padding(16.dp),
) {
Icon(Icons.Filled.Add, null, tint = Color.White)
}
}
I'm trying to make a UI similar to the YouTube channel UI. I've got two lazy columns (I don't know if it's the correct way or not) in a column, in which the first lazy column consists of data regarding the second lazy column and a sticky header. I've added a horizontal pager from the accompanist library in which the second lazy column exists. As expected, the first lazy column doesn't scroll. Is there any way to scroll these two lazy columns simultaneously or as a single UI component?
PS:- I've checked the related question but it doesn't solve the problem
Code:-
Column(modifier = Modifier.background(md_theme_dark_surface)) {
LazyColumn{
item {
SmallTopAppBar(
title = {
Text(
text = headerText,
style = MaterialTheme.typography.titleMedium,
fontSize = 24.sp,
color = md_theme_dark_onSurface
)
},
colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = md_theme_dark_surface)
)
AsyncImage(
model = ImageRequest.Builder(context).crossfade(true)
.data("")
.build(),
contentDescription = "null",
modifier = Modifier
.fillMaxWidth()
.height(100.dp),
onError = painterResource(id = R.drawable.image),
contentScale = ContentScale.Crop
)
Box(
modifier = Modifier
.padding(top = 15.dp)
.fillMaxWidth()
.wrapContentHeight(),
contentAlignment = Alignment.Center
) {
Text(
text = "Cover-art stolen from xyz from abc",
style = MaterialTheme.typography.titleMedium,
fontSize = 16.sp,
color = md_theme_dark_onSurface
)
}
}
stickyHeader {
ScrollableTabRow(
selectedTabIndex = pagerState.currentPage,
containerColor = md_theme_dark_surface
) {
tabsList.forEachIndexed { index, tabsData ->
Tab(
selected = pagerState.currentPage == index, onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}.start()
}, modifier = Modifier.padding(20.dp)
) {
Text(
text = tabsData.name,
style = MaterialTheme.typography.titleMedium,
color = md_theme_dark_onSurface,
fontSize = 17.sp
)
}
}
}
}
}
HorizontalPager(count = tabsList.size, state = pagerState) {
LazyColumn{
itemsIndexed(fetchedData) { index, dataItem ->
if (!dataItem.data.is_video && dataItem.data.url.contains(
regex = Regex(
"/i.redd.it"
)
)
) {
val screensList = subHomeScreensList
screensList[pagerState.currentPage].composable()
}
}
}
}
}
Screen recording of current code output.
How can I solve this problem, Thank you :)
I have a search bar with textfield when I try to set background color to white it comes with gray but I can make it to other colors only white not working if I change Textfiled to BasicTexfield it works fine but can't set the Icon top start
#Composable
fun DoctorListScreen(
navController: NavController,
viewModel: DoctorListViewModel = hiltViewModel()
) {
Surface(
color = Color.White,
modifier = Modifier.fillMaxSize(1f)
) {
Column {
Spacer(modifier = Modifier.padding(top = 15.dp))
SearchBar(
hint = "Klinik ara..", modifier = Modifier
.fillMaxWidth()
.padding(15.dp)
) {
}
CheckGender(modifier = Modifier.padding(15.dp))
}
}
}
#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) {
TextField(value = text, onValueChange = {
text = it
onSearch(it)
}, leadingIcon = {
Icon(painter = painterResource(id = R.drawable.search), contentDescription = null)
}, maxLines = 1,
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.shadow(5.dp, shape = RoundedCornerShape(10.dp))
.background(Color.White, shape = RoundedCornerShape(10.dp))
.onFocusChanged {
isHintDisplayed = it.isFocused != true && text.isEmpty()
})
if (isHintDisplayed) {
Text(
text = hint,
color = Color.LightGray,
modifier = Modifier.padding(horizontal = 50.dp, vertical = 16.dp)
)
}
}
}
how it looks like :
both background and bar color is white but seems different
Remove the background modifier:
//background(Color.White, shape = RoundedCornerShape(10.dp))
and use:
TextField(
/* .... */
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White),
)
Add this line in your Textfield:
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.White)