Let's consider the following #Composable functions:
#Composable
fun WelcomeScreen() {
...
ButtonTheme {
Button(...) {...}
}
}
#Composable
#Preview
fun MockWelcome() {
AppTheme {
WelcomeScreen { }
}
}
#Composable
#Preview
fun MockDarkWelcome() {
AppTheme(darkTheme = true) {
WelcomeScreen { }
}
}
And theme (note: AppTheme follows the same logic):
#Composable
fun ButtonTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: #Composable () -> Unit) {
MaterialTheme(
...
colors = if (darkTheme) darkButtonColorPalette else lightButtonColorPalette,
)
}
The preview window will show both WelcomeScreen versions correctly but the dark version will not show the button in the dark theme.
Running the app everything is OK, this it's only a preview "problem".
So, my question is: is this intended behaviour, a bug, or a misconfiguration?
Full code here: https://github.com/GuilhE/JetpackChallenge
If you join together the previews and screen together you effectively have something like this:
AppTheme(darkTheme = true) {
ButtonTheme {
Button(...) {...}
}
}
So the ButtonTheme will always be used no matter what theme you use in preview - the preview theme is overridden always.
To make the previews work as you want you'd need to abstract ButtonTheme outside of WelcomeScreen so something like this:
#Composable
fun MyApp() {
...
MyTheme {
WelcomeScreen()
}
}
#Composable
fun WelcomeScreen() {
...
Button(...) {...}
}
#Composable
#Preview
fun MockWelcome() {
AppTheme {
WelcomeScreen { }
}
}
#Composable
#Preview
fun MockDarkWelcome() {
AppTheme(darkTheme = true) {
WelcomeScreen { }
}
}
Related
So I used https://m3.material.io/theme-builder#/custom to create a theme, I downloaded it, and I'm using it. But it only ever shows light colors.
AppTheme.kt
#Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: #Composable() () -> Unit
) {
val colors = if (!useDarkTheme) {
LightColors
} else {
DarkColors
}
MaterialTheme(
colorScheme = colors,
content = content
)
}
MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onStart() {
super.onStart()
Koin.init(context = this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
AppTheme(useDarkTheme = true) {
NavHost(
navController = navController,
startDestination = Screen.Home.route
) {
addHomeTopLevel(navController)
}
}
}
}
}
HomeScreen.kt
#Composable
fun HomeScreen(
navController: NavController
) {
val viewModel: HomeViewModel by inject(HomeViewModel::class.java)
HomeContent()
}
#Composable
private fun HomeContent() {
Scaffold(
backgroundColor = MaterialTheme.colors.background,
topBar = {
TopAppBar {
Text("Hello World!")
}
},
content = {
Text("Hello Wolrd")
}
)
}
My emulator is in dark mode, but it's still showing light colors. The color values are correct, and they're part of LightColors and DarkColors correctly. The boolean is correct, and even if I change both to DarkColors it still shows light ones.
I'm not sure what I'm doing wrong here.
I have an BaseUi class for my custom views and my activities extends from it.
whe i using Root function , application crashed.
BaseUi.kt
#ExperimentalAnimationApi
open class BaseUi : AppCompatActivity() {
#Composable
fun RtlView(content: #Composable () -> Unit) {
CompositionLocalProvider(
LocalLayoutDirection provides LayoutDirection.Rtl,
content = content
)
}
#Composable
fun LtrView(content: #Composable () -> Unit) {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
content()
}
}
#Composable
fun Root(
content: #Composable () -> Unit
) {
KasbTheme {
Box(
Modifier
.fillMaxSize()
.background(LightPageBackground)
.padding(Dimen.pagePadding)
){
content()
}
}
}
}
SplashActivity.kt
#ExperimentalAnimationApi
class SplashActivity : BaseActivity() {
val viewModel = SplashActivityViewModel()
#ExperimentalAnimationApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
InitUI()
}
}
#ExperimentalAnimationApi
#Preview(showBackground = true)
#Composable
fun InitUI() {
Root {
RtlView {
Box(Modifier.fillMaxSize()) {
Image(
painter = painterResource(id = R.drawable.logo),
contentDescription = "",
modifier = Modifier.size(200.dp).align(Alignment.Center)
)
}
}
}
}
}
Runtime error
com.kasb.android E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.kasb.android, PID: 22387
java.lang.ClassCastException: androidx.compose.runtime.internal.ComposableLambdaImpl cannot be cast to kotlin.jvm.functions.Function0
at com.kasb.android.ui.activity.SplashActivity.InitUI(SplashActivity.kt:76)
at com.kasb.android.ui.activity.SplashActivity$onCreate$1.invoke(SplashActivity.kt:30)
at com.kasb.android.ui.activity.SplashActivity$onCreate$1.invoke(SplashActivity.kt:29)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.ui.platform.ComposeView.Content(ComposeView.android.kt:384)
not a permanent fix, but clean project gets rid of the error for one compile. Don't know why it's happening though.
I had same error, and problem was caused that I was calling function form subtype of the class where it was defined
BaseActivity{
fun displayAlertDialog(content: #Composable() () -> Unit) {
bottomDialog.show(supportFragmentManager, "bottom-dialog")
bottomDialog.setContent(content)
}
#Composable
fun Screen(
activity: BaseActivity,
) {
activity.displayAlertDialog{}
}
// works fine
//if activity is subtype of BaseActivity it throws that error
I wanted to build a very simple demo. A button which you can click, and it counts the clicks.
Code looks like this:
class MainActivity : ComponentActivity() {
private var clicks = mutableStateOf(0)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(color = MaterialTheme.colors.background) {
NewsStory(clicks.value) { onClick() }
}
}
}
private fun onClick() {
clicks.value++
}
}
#Composable
fun NewsStory(clicks: Int, onClick: () -> Unit) {
Column(modifier = Modifier.padding(8.dp)) {
Button(onClick = onClick) {
Text("Clicked: $clicks")
}
}
}
From my understanding this should be recomposed everytime the button is clicked, as clicks is changed.
But it does not work, any ideas what I'm doing wrong here?
I'm on androidx.activity:activity-compose:1.3.0-beta01, kotlin 1.5.10 and compose version 1.0.0-beta08
You need to use the "remember" keyword for the recomposition to happen each time, as explained here: https://foso.github.io/Jetpack-Compose-Playground/general/state/
In short, your composable would look like this:
#Composable
fun NewsStory (){
val clickState = remember { mutableStateOf(0) }
Column (modifier = Modifier.padding(8.dp)) {
Button(
onClick = { clickState.value++ }) {
}
Text("Clicked: $clickState.value.toString()")
}
}
There is a similar question Another similar question.
But it doesn't solve my problem.
I get this error "#Composable invocations can only happen from the context of a #composable function" after building my project, even though the preview is working fine.
This is my code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp {
SplashUI()
}
}
}
#Composable
fun SplashUI() {
Image(painterResource(R.drawable.logo_voodlee),"content description")
}
#Composable
fun MyApp(content: #Composable () -> Unit) {
MaterialTheme {
Surface(color = Color.Yellow) {
content()
}
}
}
#Preview("MyScreen preview")
#Composable
fun DefaultPreview() {
MyApp {
SplashUI()
}
}
Been stuck at this for hours.
Please help me fix this!!!
Found the solution. I had imported the wrong setContent, and had missed adding the dependency "androidx.activity:activity-compose:1.3.0-alpha05"
Added it, and then imported the right setContent, i.e androidx.activity.compose.setContent - this solved the issue.
I have tried to basic composable codelab exercise. In Android Studio BasicCodelabThemes shows as an error. Please help me to find the error
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp {
Greeting("Android")
}
}
}
}
#Composable
fun MyApp(content:#Composable () -> Unit) {
BasicsCodelabTheme {
Surface(color = Color.Yellow) {
content()
}
}
}
#Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
Yeah from my research on the BasicCodelabTheme, it is a custom-built composable function, it isn't a predefined one, so you need to create it yourself in your Kotlin file as a composable function for your theme.BasicCodelabTheme function definition