What is this "provides" syntax in this kotlin jetpack compose code sample? - android

What is the "provides" syntax in this code sample and what does it do?
LocalContentAlpha provides ContentAlpha.medium
It doesn't seem to be a standard kotlin keyword and I haven't had much luck googling for queries like "kotlin provides keyword" or "jetpack compose provides".
This shows up on the Jetpack Compose codelab, full snippet below.
#Composable
fun PhotographerCard() {
Column {
Text("Alfred Sisley", fontWeight = FontWeight.Bold)
// LocalContentAlpha is defining opacity level of its children
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text("3 minutes ago", style = MaterialTheme.typography.body2)
}
}
}
#Preview
#Composable
fun PhotographerCardPreview() {
LayoutsCodelabTheme {
PhotographerCard()
}
}

This is an example of an infix function:
Functions marked with the infix keyword can also be called using the infix notation (omitting the dot and the parentheses for the call).
As seen by the existence of the infix keyword on the method's documentation.
So the method could be called normally as LocalContentAlpha.provides(ContentAlpha.medium), but the infix notation allows for those extra syntax characters to be dropped.

Related

Passing argument 1f to fillMaxSize() - Purpose?

I have seen this in another person's code:
#Composable
fun UsingFraction() {
Column(modifier = Modifier
.fillMaxSize(1f)
.background(Color(0xff888888))) {
Text(text = "Testing, fraction 123 ...")
}
}
What's the purpose of the fraction-argument "1f" in this specific case?
I know, that it is for distributing available space. But I could find no difference, when I had it in or when I removed it. Concerning the shown snippet.
Default parameter for fillMaxSize() is 1.0f, therefore you don't see any difference.
Checkout the documentation for more details;
https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier#(androidx.compose.ui.Modifier).fillMaxSize(kotlin.Float)

What is the exact meaning of 'emit' in Android Jetpack Compose?

The word emit is often used in Jetpack Compose's documentation or codelabs, as follows:
The function doesn't return anything. Compose functions that "emit" UI do not need to return anything, because they describe the desired screen state instead of constructing UI widgets.
What is the exact meaning of emit in Android Jetpack Compose?
Who handles the UI emitted by the Compose function? Does the Compose framework detect and process the emitted UI?
Is there documentation with information on how and by whom the emitted UI is handled?
"Emit" means that Compose inserts a new group into the current composition.
See the source code:
#Suppress("NONREADONLY_CALL_IN_READONLY_COMPOSABLE", "UnnecessaryLambdaCreation")
#Composable inline fun <T : Any, reified E : Applier<*>> ReusableComposeNode(
noinline factory: () -> T,
update: #DisallowComposableCalls Updater<T>.() -> Unit
) {
if (currentComposer.applier !is E) invalidApplier()
currentComposer.startReusableNode() // <--- EMITTING THE NODE
if (currentComposer.inserting) {
currentComposer.createNode { factory() }
} else {
currentComposer.useNode()
}
currentComposer.disableReusing()
Updater<T>(currentComposer).update()
currentComposer.enableReusing()
currentComposer.endNode()
}

Reuse a single set of preview annotations in Jetpack Compose across composable functions

Taking first steps in Jetpack Compose, which is quite amazing except one annoying issue.
I have a constant set of previews: Normal, Dark and RTL:
#Preview(
name = "Normal",
group = "Screen",
showBackground = true
)
#Preview(
name = "Dark",
group = "Screen",
showBackground = true,
uiMode = Configuration.UI_MODE_NIGHT_YES
)
#Preview(
name = "RTL",
group = "Screen",
showBackground = true,
locale = "iw"
)
#Composable
fun JustAComposable() {
...
}
Let's just say, for example that I preview 50 composable functions. I need to copy-paste this set 50 times, which is absolutely incorrect.
Annotation inheritance is forbidden, so my question is: did anybody find a way to reuse the same set of previews across all composable functions?
The only 2 solutions which I could think of are:
To use multiple custom previews only while developing.
Partially reuse the previews - use compile-time constants for name and group.
Edit:
I created a feature request to compose team to be able to create custom annotation and annotate the annotation with all of the previews I want to reuse.
This way I only need to use my custom annotation.
Can be tracked in Google Issue Tracker
The accepted feature request is now implemented and is available starting from Android Studio Dolphin and Jetpack Compose 1.2.0-beta01.
It is called Multipreview Annotation. More information about this feature can be found here.
In order to use this feature, you must create a custom annotation class.
#Preview(
name = "small font",
group = "font scales",
fontScale = 0.5f
)
#Preview(
name = "large font",
group = "font scales",
fontScale = 1.5f
)
annotation class FontScalePreviews
and now you can apply this annotation class. For example:
#FontScalePreviews
#Composable
fun HelloWorldPreview() {
Text("Hello World")
}

Why can't I use `AnimatedVisibility` in a `BoxScope`?

I have a layout which looks like this:
Row {
...
Box(
modifier = Modifier
.fillMaxHeight()
.width(50.dp)
) {
AnimatedVisibility(
visible = isSelected && selectedAnimationFinished,
enter = fadeIn(),
exit = fadeOut()
) {
...
}
}
}
But I get the compile-time error:
fun RowScope.AnimatedVisibility(visible: Boolean, modifier: Modifier = ..., enter: EnterTransition = ..., exit: ExitTransition = ..., content: AnimatedVisibilityScope.() -> Unit): Unit' can't be called in this context by implicit receiver. Use the explicit one if necessary
It appears that Kotlin finds the AnimatedVisibility function ambiguous, since Compose exposes multiple AnimatedVisibility functions with the same signature: there's a fun AnimatedVisibility with no receiver, and a fun RowScope.AnimatedVisibility which requires RowScope.
From what I can gather, Kotlin is complaining about me using the RowScope version incorrectly, but I just want to use the version with no receiver!
Using this.AnimatedVisibility also doesn't help.
The only workaround I've found that works is to fully qualify the name, like androidx.compose.animation.AnimatedVisibility(...). But I have no idea why this works.
Can anyone shed some light on this? Is there a better option I can use than fully qualifying the name?
One workaround is to use a fully qualified name:
Box {
androidx.compose.animation.AnimatedVisibility(visibile = ...) {
...
}
}
Looks like it's a bug in the language - overload resolution is not aware of #DslMarkers and such stuff. I couldn't find related issues on Kotlin bugtracker so I filed one myself - https://youtrack.jetbrains.com/issue/KT-48215.
Another workaround is creating new composable method and using it in a Row:
#Composable
fun AnimatedThings() {
Box {
AnimatedVisiblity(visible = ...) {
...
}
}
}
I had this problem too, I used StateValue for the value of the AnimatedVisibility with a default value of true.
I found out that was fixed to me by giving the StateValue a default value of false and then using LaunchedEffect to change the value to true, or by clicking on any view on the screen that changes the value to true.

Can composable functions call non-composable functions?

I saw the new Jetpack Compose in Android and decided to check it out. I have been trying to understand some basic concepts about composables.
My question is: Can composable functions call non-composable functions?
I have searched Google to no avail.
My question is: Can composable functions call non-composable functions?
Yes. Pretty much everything in Kotlin winds up as a function call, and most functions available to you are non-composable.
Here is one of Google's bits of sample Compose UI code:
#Composable
fun NewsStory() {
val image = imageResource(R.drawable.header)
Column(
modifier = Modifier.padding(16.dp)
) {
val imageModifier = Modifier
.preferredHeight(180.dp)
.fillMaxWidth()
Image(image, modifier = imageModifier,
contentScale = ContentScale.Crop)
Spacer(Modifier.preferredHeight(16.dp))
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
In that, the following functions are not #Composable:
imageResource()
Modifier.padding()
Modifier.preferredHeight()
Modifier.fillMaxWidth()
The rule is that a function marked with #Composable needs to be called by another function marked as #Composable or one of a small family of end consumers of composable functions. This is reminiscent of coroutines, where suspend functions need to be called by other suspend functions or one of a small family of end consumers of suspend functions (e.g., coroutine builders like launch()).

Categories

Resources