According to Compose's Documentation, We can add custom Modifier classes like the following:
class SpacingModifier(val space: Dp) : Modifier.Element
fun Modifier.innerSpacing(space: Dp) = this.then(SpacingModifier(space))
@Composable
fun MyListOfItems(
list: List<Model>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier = modifier) {
items(list) { model ->
ViewHolder(model)
Spacer(modifier = Modifier.height(/*I need the innerSpacing value here*/))
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewList() {
MyListOfItems(
list = listOf(
Model(text = "Hello 1", checked = true),
Model(text = "Hello 2", checked = false),
Model(text = "Hello 3", checked = true),
Model(text = "Hello 4", checked = true),
Model(text = "Hello 5", checked = false)
),
modifier = Modifier
.background(Color.Red)
.innerSpacing(16.dp) // <- My extension function here
)
}
If I have the ability to declare extension functions for the Modifier, how do I access it inside a composable in the example above?
CodePudding user response:
Modifier
is an ordered, immutable collection of modifier elements that decorate or add behavior to Compose UI elements. For example, backgrounds, padding and click event listeners decorate or add behavior to rows, text or buttons.
Modifiers are not to be interpreted directly by your Composable functions but Layout
which is root for most composable functions such as Row
, Column
, Box
, or SubcomposeLayout
which is parent for LazyColumn
, LazyRow
, or BoxWithConstraints
.
@Composable inline fun Layout(
content: @Composable () -> Unit,
modifier: Modifier = Modifier,
measurePolicy: MeasurePolicy
) {
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
val viewConfiguration = LocalViewConfiguration.current
ReusableComposeNode<ComposeUiNode, Applier<Any>>(
factory = ComposeUiNode.Constructor,
update = {
set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
set(density, ComposeUiNode.SetDensity)
set(layoutDirection, ComposeUiNode.SetLayoutDirection)
set(viewConfiguration, ComposeUiNode.SetViewConfiguration)
},
skippableUpdate = materializerOf(modifier),
content = content
)
}
@Composable
fun SubcomposeLayout(
modifier: Modifier = Modifier,
measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
) {
SubcomposeLayout(
state = remember { SubcomposeLayoutState() },
modifier = modifier,
measurePolicy = measurePolicy
)
}
You can chain your Modifiers such as
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
)
Modifier.materialShadow is also a Modifier that is chained to draw shadow based on a class called badgeState which wraps shapes, shadow and more.
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,
)
Also when you need to add multiple params to a Composable function or access these parameters you can do it as Text
Composable uses TextStyle
@Composable
fun Text(
text: String,
modifier: Modifier = Modifier,
// Other properties
style: TextStyle = LocalTextStyle.current
)
class TextStyle(
val color: Color = Color.Unspecified,
val fontSize: TextUnit = TextUnit.Unspecified,
val fontWeight: FontWeight? = null,
val fontStyle: FontStyle? = null,
val fontSynthesis: FontSynthesis? = null,
val fontFamily: FontFamily? = null,
val fontFeatureSettings: String? = null,
val letterSpacing: TextUnit = TextUnit.Unspecified,
val baselineShift: BaselineShift? = null,
val textGeometricTransform: TextGeometricTransform? = null,
val localeList: LocaleList? = null,
val background: Color = Color.Unspecified,
val textDecoration: TextDecoration? = null,
val shadow: Shadow? = null,
val textAlign: TextAlign? = null,
val textDirection: TextDirection? = null,
val lineHeight: TextUnit = TextUnit.Unspecified,
val textIndent: TextIndent? = null
)
CodePudding user response:
If you need innerspacing of child items in a LazyColumn
or a LazyRow
, you should use verticalArrangement = modifier.spacedBy(..)
or horizontalArrangement = modifier.spacedBy(...)