HelloCW
HelloCW

Reputation: 2355

How can I share info among @Composable function in Android Studio?

In order to reduce complex, I need to split a big @Composable function to small parts, and I need to share info such as variables among them.

At present, I use Code A to do it by using top variables, I don't think it's a good.

How can I share info among @Composable function in Android Studio?

Code A

private var paddingXAxis = 80f
private var paddingXLabelMargin = 8f
private var paddingYAxis =50f
private var xAxisLength = 100f
private var yAxisLength = 100f
private var maxPointCount = 40


@Composable
fun ScreenHome_Table(
    modifier: Modifier = Modifier,   
    mViewMode: SoundViewModel
) {
    Box( ) {
    
        Canvas(
            modifier = Modifier
                .fillMaxSize()
                .padding(10.dp)
        ) {
            setParameterTable(this, mContext)
            setProcess(this, uiMSoundDensity.soundList.toList())
            setMainAxis(this)  
            setChildXAxis(this, xTime)
            setChildYAxis(this)
        }
    }
}


fun setParameterTable(drawScope: DrawScope, mContext: Context) {
    with(drawScope) {
        xAxisLength = size.width - paddingXAxis * 2
        yAxisLength = size.height - paddingYAxis * 2
    }
    maxPointCount = mContext.resources.getInteger(R.integer.maxCount)
    divisionUnit = mContext.getString(R.string.divisionUnit)
     ...
}


fun setMainAxis(drawScope: DrawScope) {
    ...
}

Upvotes: 2

Views: 1158

Answers (1)

Thracian
Thracian

Reputation: 67443

You can do this by creating a class that contains properties as default Composables such as Text, TextField or Button use. A class wraps many properties.

  TextStyle(
        color = textColor,
        fontSize = fontSize,
        fontWeight = fontWeight,
        textAlign = textAlign,
        lineHeight = lineHeight,
        fontFamily = fontFamily,
        textDecoration = textDecoration,
        fontStyle = fontStyle,
        letterSpacing = letterSpacing
    )

this class is used by BasicText

fun BasicText(
    text: String,
    modifier: Modifier = Modifier,
    style: TextStyle = TextStyle.Default,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
)

TextFieldColors is another example of this

private class DefaultTextFieldColors(
    private val textColor: Color,
    private val disabledTextColor: Color,
    private val cursorColor: Color,
    private val errorCursorColor: Color,
    private val focusedIndicatorColor: Color,
    private val unfocusedIndicatorColor: Color,
    private val errorIndicatorColor: Color,
    private val disabledIndicatorColor: Color,
    private val leadingIconColor: Color,
    private val disabledLeadingIconColor: Color,
    private val errorLeadingIconColor: Color,
    private val trailingIconColor: Color,
    private val disabledTrailingIconColor: Color,
    private val errorTrailingIconColor: Color,
    private val backgroundColor: Color,
    private val focusedLabelColor: Color,
    private val unfocusedLabelColor: Color,
    private val disabledLabelColor: Color,
    private val errorLabelColor: Color,
    private val placeholderColor: Color,
    private val disabledPlaceholderColor: Color
) 

Second option is to create a class that contains properties and can act a State wrapper for other MutableStates. With this approach can trigger recomposition on any individual property change, pass or observe latest properties unlike first approach.

    class BadgeState(
        var maxNumber: Int = 99,
        var circleShapeThreshold: Int = 1,
        @IntRange(from = 0, to = 99) var roundedRadiusPercent: Int = 50,
        backgroundColor: Color,
        var horizontalPadding: Dp = 4.dp,
        var verticalPadding: Dp = 0.dp,
        textColor: Color,
        var fontSize: TextUnit,
        var fontWeight: FontWeight? = null,
        var fontFamily: FontFamily? = null,
        var fontStyle: FontStyle? = null,
        var textDecoration: TextDecoration? = null,
        var shadow: MaterialShadow? = null,
        var borderStroke: BorderStroke? = null,
        showBadgeThreshold: Int = Int.MIN_VALUE,
    ) {
{
    var backgroundColor by mutableStateOf(backgroundColor)

    /*
        Properties for Text
     */
    var textColor by mutableStateOf(textColor)

    var text by mutableStateOf("0")
        private set

    var numberOnBadge by mutableStateOf(0)
        private set

    var showBadgeThreshold by mutableStateOf(showBadgeThreshold)
    ...
}

And wrap it with remember to not create new instance on each recomposition

fun rememberBadgeState(
    maxNumber: Int = 99,
    circleShapeThreshold: Int = 1,
    @IntRange(from = 0, to = 99) roundedRadiusPercent: Int = 50,
    backgroundColor: Color = Color.Red,
    horizontalPadding: Dp = 4.dp,
    verticalPadding: Dp = 0.dp,
    textColor: Color = Color.White,
    fontSize: TextUnit = 14.sp,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    fontStyle: FontStyle? = null,
    textDecoration: TextDecoration? = null,
    shadow: MaterialShadow? = null,
    borderStroke: BorderStroke? = null,
    showBadgeThreshold: Int = Int.MIN_VALUE,
): BadgeState {
    return remember {
        BadgeState(
            maxNumber,
            circleShapeThreshold,
            roundedRadiusPercent,
            backgroundColor,
            horizontalPadding,
            verticalPadding,
            textColor,
            fontSize,
            fontWeight,
            fontFamily,
            fontStyle,
            textDecoration,
            shadow,
            borderStroke,
            showBadgeThreshold
        )
    }
}

You can pass this state between you Composables

@Composable
fun Badge(
    modifier: Modifier = Modifier,
    badgeState: BadgeState = rememberBadgeState(),
) {

    val showBadge = remember {
        derivedStateOf {
            badgeState.showBadgeThreshold < badgeState.numberOnBadge
        }
    }

    if (showBadge.value) {
        BadgeComponent(badgeState = badgeState, modifier = modifier)
    }
}

or you can pass to a Modifier you created

private fun Modifier.getBadgeModifier(
    badgeState: BadgeState,
    shape: Shape
) = this
    .materialShadow(badgeState = badgeState)
    .then(
        badgeState.borderStroke?.let { borderStroke ->
            this.border(borderStroke, shape = shape)
        } ?: this
    )
    .background(
        badgeState.backgroundColor,
        shape = shape
    )

or another one

fun Modifier.materialShadow(badgeState: BadgeState) = composed(
    inspectorInfo = {
        name = "shadow"
        value = badgeState.shadow
    },
    factory = {
   // rest of the code
}

Upvotes: 2

Related Questions