I am currently working on an Android app and I am trying to create an infinite animated progress bar using Jetpack Compose. I have been looking through the documentation but I am having trouble finding a straightforward example of how to create this. Can anyone provide a simple example or point me in the right direction to get started?"
#Composable
fun LoadingProgressBar(isLoading: Boolean) {
val animation = remember {
repeatable(periodMillis = 1000) {
animation(0f, 1f) { progress ->
progress
}
}
}
if (isLoading) animation.start() else animation.stop()
Box(modifier = Modifier.preferredSize(100.dp, 5.dp).background(color = Color.Gray)) {
Box(modifier = Modifier.preferredWidth(animation[animation] * 100.dp)
.preferredHeight(5.dp)
.background(color = Color.Blue))
}
}
CircularProgressIndicator and LinearProgressIndicator are the progressbars that can be determinate or indeterminate based on which overload you pick.
#Composable
fun CircularProgressIndicator(
/*#FloatRange(from = 0.0, to = 1.0)*/
progress: Float,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colors.primary,
strokeWidth: Dp = ProgressIndicatorDefaults.StrokeWidth
)
or
#Composable
fun CircularProgressIndicator(
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colors.primary,
strokeWidth: Dp = ProgressIndicatorDefaults.StrokeWidth
)
same goes for linear one either
Related
Is there a way to convert jetpack Compose's androidx.compose.ui.graphics.Color to android.graphics.drawable.ColorDrawable ?
I tried ColorDrawable(Color.Red.toArgb()) but its not working!
You tried it in the correct way.
Here is a sample that does work
#Composable
fun MyComposable() {
val color = androidx.compose.ui.graphics.Color.Red
AndroidView(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
factory = { context ->
View(context).apply {
background = ColorDrawable(color.toArgb())
}
}
)
}
I have a TextField on one of my app screens. When I rotate my device the text field retains the value, but not the soft keyboard focus.
How could I keep the focus and prevent the keyboard from disappearing?
Here is a simplified version of the composable for the screen:
#Composable
fun LoginScreen(
uiState: LoginUiState,
) {
MyTheme {
Surface(
modifier = Modifier
.fillMaxSize()
.verticalScroll(scrollableState)
.imePadding(),
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
TextField(
value = uiState.email,
enabled = !uiState.isLoggingIn
)
}
}
}
}
The UI state comes from the model.
You are using the a state-preserver like a ViewModel here, I suppose. You could either store the value in a rememberSaveable block, as Nikola suggests, or you could simply put a simple Boolean where you put the uiState parameter. There's no need to use MutableState<T> this way. Also, no side-effects are required. Just create a parameter.
#Composable
fun MyFiled(
loginState: ... ,
isFocused: Boolean
){
if (isFocused)
focusRequestor.requestFocus()
...
}
Just put a simple condition, and it'll do.
You need to use rememberSaveable to store wither the TextField was focused previously.
val focusRequester = remember { FocusRequester() }
var hasFocus by rememberSaveable { mutableStateOf(false) }
TextField(
value = ...,
onValueChange = { ... },
modifier = Modifier.focusRequester(focusRequester).onFocusChanged {
hasFocus = it.hasFocus
}
)
LaunchedEffect(hasFocus){
if(hasFocus) {
focusRequester.requestFocus()
}
}
I'm new to Jetpack Compose and trying to experiment with theming.
I have a theme.kt file that looks like this:
#Composable
fun AppThemeProvider(
content: #Composable () -> Unit
) = CompositionLocalProvider(
LocalColors provides Colors(),
LocalShapes provides Shapes(),
LocalTypography provides Typography(),
content = content
)
object AppTheme {
val colors: Colors #Composable get() = LocalColors.current
val shapes: Shapes #Composable get() = LocalShapes.current
val typography: Typography #Composable get() = LocalTypography.current
}
And 3 classes for each provided values: Colors.kt, Shapes.kt and Typography.kt
This is my Colors class (The other 2 are basically the same):
data class Colors(
val primary: Color = Color(0xFF00663f),
val primaryVariant: Color = Color(0xFF007265),
val onPrimary: Color = Color(0xFFFFFFFF),
val secondary: Color = Color(0xFFFFFFFF),
val secondaryVariant: Color = Color(0xFFFFFFFF),
val onSecondary: Color = Color(0xFFFFFFFF),
val background: Color = Color(0xFFFFFFFF),
val surface: Color = Color(0xFFFFFFFF),
val error: Color = Color(0xFFBF0013),
val onBackground: Color = Color(0xFF3E3E3E),
val onError: Color = Color(0xFFFFFFFF),
)
val LocalColors = staticCompositionLocalOf { Colors() }
val colors: Colors
#Composable
#ReadOnlyComposable
get() = LocalColors.current
Now, I have an API that I call during the splash screen that returns my theme as a JSON structure.
I'd like to use such response to build my 3 values classes to have a 'built-at-runtime' theme.
Is it possible to achieve this behaviour?
Yes it is possible. You can pass the Colors as a parameter to your AppThemeProvider composable and when the colors changes then the theme of your up will be updated.
Simple example:
var colors by remember { mutableStateOf(Colors()) }
LaunchedEffect(Unit) {
colors = downloadColorsFromAPI()
}
AppThemeProvider(colors = colors) {
App()
}
and your AppThemeProvider becomes:
#Composable
fun AppThemeProvider(
colors: Colors = Colors(),
content: #Composable () -> Unit
) = CompositionLocalProvider(
LocalColors provides colors,
LocalShapes provides Shapes(),
LocalTypography provides Typography(),
content = content
)
I'm using Glide in an Android, Kotlin, Jetpack project. When the photos are loading, the DEFAULT_MOVIE_IMAGE appears. However if one of the movies that is returned has a null value for an image URL, no image appears and the card shrinks down to the size of only the title. I'm trying to set it so the DEFAULT_MOVIE_IMAGE will appear if there is a null value for the movie poster url.
Setting a placeholder or an error image does not appear to be working.
Image part of the MovieCard composable
movie.posterPath?.let { url ->
val image = loadPicture(url = url, defaultImage = DEFAULT_MOVIE_IMAGE).value
image?.let { img ->
Image(
bitmap = img.asImageBitmap(),
contentDescription = "Movie Projector",
modifier = Modifier
.fillMaxWidth()
.height(450.dp),
contentScale = ContentScale.Fit
)
}
ImageUtils.kt
const val DEFAULT_MOVIE_IMAGE = R.drawable.movie_placeholder
const val POSTER_BASE_URL = "https://image.tmdb.org/t/p/w500"
#Composable
fun loadPicture(
url: String,
#DrawableRes defaultImage: Int
): MutableState<Bitmap?> {
val bitmapState: MutableState<Bitmap?> = remember { mutableStateOf(null) }
Glide.with(LocalContext.current)
.asBitmap()
.load(defaultImage)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
bitmapState.value = resource
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
Glide.with(LocalContext.current)
.asBitmap()
.load("https://image.tmdb.org/t/p/w500$url")
.error(R.drawable.space_dog_laika1)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
bitmapState.value = resource
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
return bitmapState
}
I ended up wrapping the image piece of the movie card in an if/else statement. I'm not sure if this is best practice or the most terse solution, but it worked.
if (movie.posterPath != null) {
movie.posterPath?.let { url ->
val image = loadPicture(url = url, defaultImage = DEFAULT_MOVIE_IMAGE).value
image?.let { img ->
Image(
bitmap = img.asImageBitmap(),
contentDescription = "Movie Poster",
modifier = Modifier
.fillMaxWidth()
.height(450.dp),
contentScale = ContentScale.Fit
)
}
}
} else {
val image: Painter = painterResource(id = DEFAULT_MOVIE_IMAGE)
Image(
painter = image,
contentDescription = "Film Projector",
modifier = Modifier
.fillMaxWidth()
.height(450.dp),
contentScale = ContentScale.Fit
)
}
I am trying to run a simple LazyColumn Object, but am unable to run it without this weird error.
Here is my code:
#Composable
fun Test(){
LazyColumn() {
Text(text = "Placeholder", fontSize= 30.sp)
Spacer(modifier = Modifier.padding(10.dp))
}
}
Here are the errors:
org.jetbrains.kotlin.diagnostics.SimpleDiagnostic#74c0fa2 (error: could not render message)
org.jetbrains.kotlin.diagnostics.SimpleDiagnostic#c077eec3 (error: could not render message)
Is it something wrong with my code, or is it a bug?
*I wanted to test the scroll function by copy and pasting the lines after the LazyColumn() statement over and over
With 1.0.0-beta04 you can use:
val itemsList = (0..50).toList()
LazyColumn() {
items(itemsList) {
Text(text = "Placeholder", fontSize = 30.sp)
Spacer(modifier = Modifier.padding(10.dp))
}
}
In the LazyListScope in order to display the items you have to use one the provided functions:item, items, itemsindexed and stickyHeader.
The error studio should be showing is #Composable invocations can only happen from the context of a #Composable function; this is the error you get when you would compile this function. That Studio shows (error: could not render message) is a known bug that the team is working on.
The reason the compose compiler plugin generates this error is the lambda expected by LazyColumn is not a composable lambda but is the LazyList DSL in which the column is described. For example, something like,
#Composable
fun Test(){
LazyColumn() {
items(10_000) {
Text(text = "Placeholder $it", fontSize = 30.sp)
Spacer(modifier = Modifier.padding(10.dp))
}
}
}
is probably what you wanted. It doesn't create 10,000 items, it only creates enough to fit on the screen and will create additional rows as needed (discarding rows as they are occluded) up to row 9,999.
Try this:
#Composable
fun Test(){
LazyColumn() {
for (i in 1..10) {
TestItem(i)
}
}
}
#Composable
fun TestItem(i: Int) {
Text(text = "Placeholder $i", fontSize = 30.sp)
Spacer(modifier = Modifier.padding(10.dp))
}