mirror of
https://github.com/BetterAndroid/FlexiUI.git
synced 2025-09-08 19:44:25 +08:00
feat: add CheckBox
This commit is contained in:
@@ -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
|
@@ -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
|
|
Reference in New Issue
Block a user