feat: add CheckBox

This commit is contained in:
2023-11-10 23:05:43 +08:00
parent 850c8f070d
commit ba85419e16
2 changed files with 178 additions and 26 deletions

View File

@@ -0,0 +1,178 @@
/*
* Flexi UI - A flexible and useful UI component library.
* Copyright (C) 2019-2023 HighCapable
* https://github.com/BetterAndroid/FlexiUI
*
* Apache License Version 2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is created by fankes on 2023/11/9.
*/
@file:Suppress("unused")
package com.highcapable.flexiui.component
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.highcapable.flexiui.LocalColors
import com.highcapable.flexiui.LocalSizes
import com.highcapable.flexiui.interaction.clickable
import com.highcapable.flexiui.resources.IconRes
import com.highcapable.flexiui.utils.borderOrNot
import org.jetbrains.compose.resources.painterResource
@Immutable
data class CheckBoxColors(
val contentColor: Color,
val inactiveColor: Color,
val activeColor: Color
)
@Immutable
data class CheckBoxStyle(
val contentSize: Dp,
val strokeSize: Dp,
val pressedGain: Float,
val hoveredGain: Float,
val shape: Shape,
val border: BorderStroke
)
@Composable
fun CheckBox(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
colors: CheckBoxColors = CheckBox.colors,
style: CheckBoxStyle = CheckBox.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
contentSpacing: Dp = CheckBox.contentSpacing,
content: @Composable () -> Unit = {}
) {
val hovered by interactionSource.collectIsHoveredAsState()
val pressed by interactionSource.collectIsPressedAsState()
val animatedStrokeScale by animateFloatAsState(if (pressed) 0.9f else 1f)
val animatedColor by animateColorAsState(if (checked) colors.activeColor else colors.inactiveColor)
val animatedContentScale by animateFloatAsState(if (hovered) 1.1f else 1f)
val animatedContentAlpha by animateFloatAsState(if (checked) 1f else 0f)
val animatedContentLayer by animateFloatAsState(if (checked) 1f else 0f)
val sModifier = if (enabled) modifier else modifier.alpha(0.5f)
Row(modifier = sModifier, verticalAlignment = Alignment.CenterVertically) {
val cModifier = if (enabled)
Modifier.clickable(
enabled = enabled,
interactionSource = interactionSource
) { onCheckedChange(!checked) }
else Modifier.alpha(0.5f)
Box(
modifier = cModifier.size(style.strokeSize)
.scale(animatedStrokeScale)
.background(animatedColor, style.shape)
.borderOrNot(style.border, style.shape),
contentAlignment = Alignment.Center
) {
Icon(
modifier = Modifier.size(style.contentSize)
.scale(animatedContentScale)
.alpha(animatedContentAlpha)
.graphicsLayer(
clip = true,
scaleX = animatedContentLayer,
scaleY = animatedContentLayer
),
painter = painterResource(IconRes.CHECKMARK),
tint = colors.contentColor
)
}
Box(
modifier = Modifier.padding(start = contentSpacing)
.clickable(enabled = enabled) { onCheckedChange(!checked) }
) { content() }
}
}
object CheckBox {
val colors: CheckBoxColors
@Composable
@ReadOnlyComposable
get() = defaultCheckBoxColors()
val style: CheckBoxStyle
@Composable
@ReadOnlyComposable
get() = defaultCheckBoxStyle()
val contentSpacing: Dp
@Composable
@ReadOnlyComposable
get() = defaultCheckBoxContentSpacing()
}
@Composable
@ReadOnlyComposable
private fun defaultCheckBoxColors() = CheckBoxColors(
contentColor = Color.White,
inactiveColor = LocalColors.current.themeTertiary,
activeColor = LocalColors.current.themePrimary
)
@Composable
@ReadOnlyComposable
private fun defaultCheckBoxStyle() = CheckBoxStyle(
contentSize = DefaultContentSize,
strokeSize = DefaultStrokeSize,
pressedGain = DefaultPressedGain,
hoveredGain = DefaultHoveredGain,
shape = DefaultCheckBoxShape,
border = defaultCheckBoxBorder()
)
@Composable
@ReadOnlyComposable
private fun defaultCheckBoxBorder() = BorderStroke(LocalSizes.current.borderSizeTertiary, LocalColors.current.textPrimary)
@Composable
@ReadOnlyComposable
private fun defaultCheckBoxContentSpacing() = LocalSizes.current.spacingSecondary
private val DefaultContentSize = 13.dp
private val DefaultStrokeSize = 20.dp
private val DefaultCheckBoxShape = RoundedCornerShape(4.dp)
private const val DefaultPressedGain = 0.9f
private const val DefaultHoveredGain = 1.1f

View File

@@ -1,26 +0,0 @@
/*
* Flexi UI - A flexible and useful UI component library.
* Copyright (C) 2019-2023 HighCapable
* https://github.com/BetterAndroid/FlexiUI
*
* Apache License Version 2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is created by fankes on 2023/11/9.
*/
@file:Suppress("unused")
package com.highcapable.flexiui.component
// TODO: To be implemented