Is there any way to use a JSON animation file using LottieAnimation in Jetpack Compose for an interactive element such as a to-do list's checkmark so that it animates when clicked?
I currently have a Row with Icon and a Column that further contains title and subtitle. I want this Icon to have a Lottie Animation.
You can use the LottieAnimation composable.
Something like:
var isPlaying by remember { mutableStateOf(false) }
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
val progress by animateLottieCompositionAsState(
composition,
isPlaying = isPlaying,
)
Row(verticalAlignment = Alignment.CenterVertically) {
LottieAnimation(
composition = composition,
progress = { progress },
modifier = Modifier.clickable{ isPlaying = !isPlaying }
)
Text("Title", )
}
Related
I have a page that I want to be scrollable (mostly text only, no list). At the bottom of that page I have a disabled button, but when I reach the bottom of the page I want that button to activate. How can I do this with JetpackCompose Kotlin androidx.compose.ui version 1.3.2?
Much appreciation in advance!
I can't use ScrollableColumn, Scrollable, LazyColumn, LazyRow because of the compose library.
It's not clear why you can't use these components since they are all part of the Compose library. However, this can be done using Column composable with verticalScroll modifier.
val scrollState = rememberScrollState()
Column(Modifier.verticalScroll(scrollState)) {
//Text
}
State for enabling Button, false by default:
val isButtonEnabled by remember {mutableStateOf(false)}
ScrollState has canScrollForward Boolean property, false means we cannot scroll forward (we are the end of the list). Once we have false here, button should be enabled
LaunchedEffect(scrollState.canScrollForward) {
if (!scrollState.canScrollForward) isButtonEnabled = true
}
And button:
Button(enabled = isButtonEnabled, ...)
#Composable
override fun Build() {
val scrollState = rememberScrollState()
val isButtonEnabled by remember {mutableStateOf(false)}
LaunchedEffect(scrollState.canScrollForward) {
if (!scrollState.canScrollForward) isButtonEnabled = true
}
ScreenScaffold(
header = {
TopBar(
title = R.string.insurance_choose_insurance_travel,
onBack = { sendNavEffect.invoke(Effect.Navigation.OnBack) },
actions = {},
backgroundColor = white
)
},
page = {
Column(
Modifier
.fillMaxSize()
.padding(20.dp)
.verticalScroll(scrollState)
){
repeat(100){
Text(
"Text",
color = Color.Black
)
}
}
},
footer = {
Row(modifier = Modifier.padding(20.dp)) {
PrimaryActionButton(
text = R.string.accept_terms_and_conditions_sca.getString(),
buttonState = if(isButtonEnabled) ButtonState.Active else ButtonState.Disabled,
onClick = {}
)
}
})
}
}
I new to Jetpack compose and i'am creating a view to download a file from my api, i have a call back to give me the % or the download and i would like it display it on a progress bar. The problem is that everytime i update the progressbar, it seems to update all my view causing multiples call to my api. Here is my code :
#Composable
fun DownloadView() {
val isDownloading = remember { mutableStateOf(false) }
var downloadProgress by remember { mutableStateOf(0.1f) }
val animatedProgress = animateFloatAsState(
targetValue = downloadProgress,
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
).value
println("Recompose view") //this is called 100+ times
Button(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(id = R.color.blue)),
onClick = {
println("click download")
if (!isDownloading.value) {
isDownloading.value = true
Api.download() //stating the download from my api
downloadProgress = Api.callback() //call back of the download progress
//when api is done i also get a call back the i set isDownloading.value = false
}
}
},) {
var text = "Download"
if (isDownloading.value) {
text = "Downloading"
}
Text(text = text, color = Color.White)
if (isDownloading.value) {
CircularProgressIndicator(
animatedProgress,
color = colorResource(id = R.color.orange),
modifier = Modifier.size(28.dp).padding(start = 4.dp)
)
}
}
}
This is working, i got my button with the progress, it change the button text when i'am downloading and i update the progress bar. The problem is that my whole view is updated everytime the value of the progress is update. Is there a way to avoid this or did i missunderstand something ? Thanks for the help.
I am building an onboarding fragment that gives users tips for each screen. there are multiple pages of a few lines:
Page 1
this icon does this
that icon does that
Button: Next
Page 2
this icon does this
that icon does that
Button: Finish
I want each view on the page to fade in progressively down the screen.
Then with a new page i want the items to reset and all fade in again from the top down.
I have tried using AnimatedVisibility but the problem is that elements keep their state so the fade effect doesnt play on the second page. Possibly AnimatedVisibility isnt the right choice for what i want to do?
So this is the code for a line. I want to reset the state object on each recomposition.
Or if someone has a better suggetion on how to do it - then that would also be excellent.
#Composable
private fun Line(line: ActionResources, modifier: Modifier) {
val state = remember {
MutableTransitionState(false).apply {
// Start the animation immediately.
targetState = true
}
}
AnimatedVisibility(state,
enter = fadeIn(animationSpec = tween(durationMillis = 1000)),
exit = fadeOut(animationSpec = tween(durationMillis = 1000))
) {
Row(
modifier = modifier
.padding(16.dp)
) {
val color = line.color?.let { colorResource(it) } ?: MaterialTheme.colors.onSurface
line.icon?.also {
Icon(
painter = painterResource(it),
tint = color,
contentDescription = stringResource(id = R.string.menu_search),
modifier = Modifier.padding(end = 8.dp).size(24.dp)
)
}
line.label?.also {
Text(
modifier = Modifier,
style = MaterialTheme.typography.body1,
color = color,
text = it
)
}
}
}
}
I can't compile your code especially ActionResources, but based on this
I want to reset the state object on each recomposition.
I can only suggest supplying a key to your remember {...} using the the line parameter.
val state = remember (line) {
MutableTransitionState(false).apply {
// Start the animation immediately.
targetState = true
}
}
I'm not sure if this would solve your problem, but if you want this state to be re-calculated assuming the line parameter will always be different on succeeding re-compositions, then using it as remember {...}'s key will guarantee a re-calculation.
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
I have Tab Layout with multiple fragments and I would like to display a Popup only when a specific screen is being displayed. I am using the Jetpack Compose Popup component.
I followed the docs and currently the popup is always being displayed regardless the fragment is being displayed, but I want to show the Popup only when a specific screen is being displayed.
Popup code:
Box {
val popupWidth = 200.dp
val popupHeight = 50.dp
val cornerSize = 16.dp
Popup(alignment = Alignment.Center) {
// Draw a rectangle shape with rounded corners inside the popup
Box(
Modifier
.size(popupWidth, popupHeight)
.background(Color.White, RoundedCornerShape(cornerSize))
)
}
}
Sorry to revive an old thread but for completeness sake, try using a boolean and an if statement that is true when you want the popup to be shown.
var showPopup by remember { mutableStateOf(false) }
val popupWidth = 200.dp
val popupHeight = 50.dp
val cornerSize = 16.dp
if (showPopup) {
Popup(alignment = Alignment.Center, onDismissRequest = { showPopup = false }) {
Box(modifier = Modifier.size(popupWidth, popupHeight).background(Color.white, RoundedCornerShape(cornerSize)) {
// content
}
}
}