Is there any way to use `R.attr` references in a C...
# compose
z
Is there any way to use
R.attr
references in a Compose Preview? We use attribute references & themes for colors/drawables/text styles, however when running a preview they don’t resolve properly. This Composable fails to render a Preview.
Copy code
@Preview
@Composable
fun MyComposable() {
   val attrPainter = attrPainter(R.attr.myAttr) //custom painter to get a drawable from an attr reference
   Image(attrPainter, contentDescription = "some description")
}
m
Preview mode is not exact. There's a lot of things that it can't do. Keep in mind that when running this preview, how would AS know what theme to run your preview against? There's no way (unlike the xml previewer) to select the XML theme to apply in the compose preview pane. Perhaps there might be something you can do in your preview with a ContextThemeWrapper and settings the LocalContext to that, but out of the box, there's nothing i know of.
z
yeah that’s what I figured. It would be nice for the Preview to allow you to supply a theme
m
To be honest though i haven't had much need to query the xml theme at all. But i've generally been working with new activities when working with compose. I haven't been focusing on activities that are hybrid
Personally, i would just extend the compose material theme to completely avoid the xml theme altogether.
Copy code
interface MyDrawables {
    val zoom: Int
}

val LocalMyDrawables = staticCompositionLocalOf<MyDrawables> { 
    object: MyDrawables {
        override val zoom: Int
            get() = R.drawable.cl_ic_zoom_outline
    }
}


val MaterialTheme.myDrawables @Composable get() = LocalMyDrawables.current
And wherever you setup your MaterialTheme, you’ll probably want to allow the caller to pass an instance of MyDrawables.
Copy code
@Composable
fun MyTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    drawables: MyDrawables = object : MyDrawables {
        override val zoom: Int
            get() = R.drawable.cl_ic_zoom_outline
    },
    content: @Composable () -> Unit
) {
    MaterialTheme(colors, typography, shapes) {
        CompositionLocalProvider(
            LocalMyDrawables provides drawables
        ) {
            content()
        }
    }
}
z
yeah we have something like that for colors, we haven’t made it to drawables yet. Was hoping for something that could co-exist with our existing setup but we’ll get there eventually! thanks for taking the time to answer
m
👍
i would honestly then try the context theme wrapper thing, and just make it a reusable function for your previews and see if it works for you
Copy code
@Preview
@Composable
fun MyPreview() {
    val context = LocalContext.current
    val wrapper = ContextThemeWrapper(context, R.style.Theme_MaterialComponents)
    CompositionLocalProvider(
        LocalContext provides wrapper
    ) {
        Box(modifier = Modifier
            .size(50.dp)
            .background(attrColorResource(attrId = R.attr.colorPrimary))) {

        }
    }
}

@Composable
fun attrColorResource(attrId: Int): Color {
    val context = LocalContext.current
    val attrs = context.theme.obtainStyledAttributes(intArrayOf(attrId))
    val colorValue = attrs.getColor(0, 0)
    return Color(colorValue)
}
if you switch from R.style.Theme_MaterialComponents to R.style.Theme_MaterialComponents_Light you’ll see the color change in the preview
z
oh nice! i will give this a shot. thank you Matthew!
it worked! I ended up rolling it into our theme (behind a check for “isPreview”) so that all previews will get the theme as long as they use our Theme
thanks again!
260 Views