diff --git a/compose/src/main/java/org/zhiwei/compose/model/Screen.kt b/compose/src/main/java/org/zhiwei/compose/model/Screen.kt index d2444eb..4920a89 100644 --- a/compose/src/main/java/org/zhiwei/compose/model/Screen.kt +++ b/compose/src/main/java/org/zhiwei/compose/model/Screen.kt @@ -17,6 +17,7 @@ import org.zhiwei.compose.screen.basic.material3.Text_Screen import org.zhiwei.compose.screen.basic.material3.TopAppbarTabs_Screen import org.zhiwei.compose.screen.basic.material3.Widget_Screen import org.zhiwei.compose.screen.gesture.Clickable_Screen +import org.zhiwei.compose.screen.gesture.SwipeScroll_Screen import org.zhiwei.compose.screen.gesture.TapDragGestures_Screen import org.zhiwei.compose.screen.gesture.TransformGestures_Screen import org.zhiwei.compose.screen.layout_state.ConstraintLayout_Screen @@ -173,6 +174,10 @@ internal object GestureScreenUIs { "Transforms", "对控件元素的转换操作,包括平移、缩放、旋转等。" ) { TransformGestures_Screen(modifier) }, + CourseItemModel( + "SwipeScrollable", + "Modifier的一些其他操作手势,侧滑,滚动等。" + ) { SwipeScroll_Screen(modifier) }, ) } diff --git a/compose/src/main/java/org/zhiwei/compose/screen/gesture/SwipeScrollable.kt b/compose/src/main/java/org/zhiwei/compose/screen/gesture/SwipeScrollable.kt new file mode 100644 index 0000000..c336f4f --- /dev/null +++ b/compose/src/main/java/org/zhiwei/compose/screen/gesture/SwipeScrollable.kt @@ -0,0 +1,214 @@ +package org.zhiwei.compose.screen.gesture + +import androidx.compose.animation.core.TweenSpec +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.AnchoredDraggableState +import androidx.compose.foundation.gestures.DraggableAnchors +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.anchoredDraggable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.FractionalThreshold +import androidx.compose.material.Slider +import androidx.compose.material.SwipeProgress +import androidx.compose.material.Text +import androidx.compose.material.rememberSwipeableState +import androidx.compose.material.swipeable +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import org.zhiwei.compose.ui.widget.Title_Desc_Text +import org.zhiwei.compose.ui.widget.Title_Sub_Text +import org.zhiwei.compose.ui.widget.Title_Text +import kotlin.math.roundToInt + +/** + * 作者: iOrchid + * 主页: [Github](https://github.com/iOrchid) + * 日期: 2024年05月18日 10:12 + * 签名: 天行健,君子以自强不息;地势坤,君子以厚德载物。 + * You never know what you can do until you try ! + * 演示一些拖拽,侧滑和滚动相关的一些手势事件 + */ +@Composable +internal fun SwipeScroll_Screen(modifier: Modifier = Modifier) { + Column(modifier.fillMaxSize()) { + Title_Text(title = "Swipeable") + Title_Sub_Text(title = "1. 侧滑事件的简单实现,swipeable操作符,以及替代方式的演示。") + Title_Desc_Text(desc = "swipeable的使用,设置fraction的位置不同,滑动切换的临界点就不一样。") + UI_Swipeable() + Title_Desc_Text(desc = "替代swipeable,使用推荐的新的api,AnchoredDraggable实现相同效果。") + UI_AnchoredDraggable() + } +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +private fun UI_Swipeable() { + var fraction by remember { mutableFloatStateOf(0.3f) } + + val swipeableState = rememberSwipeableState( + initialValue = 0, + confirmStateChange = { + true + } + ) + //fraction简单理解就是,滑动过渡的临界条件,在临界点之前,会返回到原点,过了临界点,就滑过去到终点 + Row(verticalAlignment = Alignment.CenterVertically) { + Text("Fraction") + Spacer(modifier = Modifier.width(8.dp)) + Slider(value = fraction, onValueChange = { fraction = it }) + } + + BoxWithConstraints(modifier = Modifier.fillMaxWidth()) { + + val width = maxWidth + val squareSize = 60.dp + + val sizePx = with(LocalDensity.current) { (width - squareSize).toPx() } + val anchors = mapOf(0f to 0, sizePx to 1) // Maps anchor points (in px) to states + Box( + modifier = Modifier + .width(width) + //可以看出swipe已经废弃,AnchoredDraggable替代api,稍后演示。 + .swipeable( + state = swipeableState, + anchors = anchors, + thresholds = { _, _ -> FractionalThreshold(fraction) }, + orientation = Orientation.Horizontal + ) + .background(Color.LightGray, RoundedCornerShape(8.dp)) + ) { + Box( + Modifier + .offset { + IntOffset(swipeableState.offset.value.roundToInt(), 0) + } + .size(squareSize) + .background(Color.Blue, RoundedCornerShape(8.dp)) + ) + } + } + + val direction: Float = swipeableState.direction + val currentValue: Int = swipeableState.currentValue + val targetValue: Int = swipeableState.targetValue + val overflow: Float = swipeableState.overflow.value + val offset: Float = swipeableState.offset.value + val progress: SwipeProgress = swipeableState.progress + + Spacer(modifier = Modifier.height(20.dp)) + Column( + modifier = Modifier + .fillMaxWidth() + .height(180.dp) + .background(Color.Blue) + ) { + + Text( + color = Color.White, + text = + "滑动方向:$direction\n" + + "动画在执行: ${swipeableState.isAnimationRunning}\n" + + "当前value: ${currentValue}\n" + + "目标value: ${targetValue}\n" + + "是否越界: ${overflow}\n" + + "偏移量: $offset\n" + + "进度: $progress" + ) + + } +} + +//使用AnchoredDraggable代替swipeable实现侧滑效果 +@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) +@Composable +private fun UI_AnchoredDraggable() { + var fraction by remember { mutableFloatStateOf(0.3f) } + + //fraction简单理解就是,滑动过渡的临界条件,在临界点之前,会返回到原点,过了临界点,就滑过去到终点 + Row(verticalAlignment = Alignment.CenterVertically) { + Text("Fraction") + Spacer(modifier = Modifier.width(8.dp)) + Slider(value = fraction, onValueChange = { fraction = it }) + } + val squareSize = 60.dp + val density = LocalDensity.current + BoxWithConstraints(Modifier.fillMaxWidth()) { + + //end的锚点位置,要放方块末端到屏幕右边,end to end + val widthPx = with(LocalDensity.current) { + (maxWidth - squareSize).toPx() + } + val anchors = DraggableAnchors { + //两个锚点 + "Start" at 0f +// "Middle" at widthPx / 2f //可以多个锚点,这里模拟加个中间锚点 + "End" at widthPx + } + val state = remember { + AnchoredDraggableState( + initialValue = "Start", + anchors = anchors, + //位置阈值,50%的位置,或者指定点 with(density) { 56.dp.toPx() } + positionalThreshold = { totalDistance: Float -> totalDistance * 0.5f }, + //速度阈值 + velocityThreshold = { with(density) { 125.dp.toPx() } }, + animationSpec = TweenSpec() + ) + } + SideEffect { + state.updateAnchors(anchors) + } + Box( + modifier = Modifier + .fillMaxWidth() + .background(Color.LightGray, RoundedCornerShape(8.dp)) + ) { + Box( + Modifier + .offset { + IntOffset( + state + .requireOffset() + .roundToInt(), 0 + ) + } + .anchoredDraggable(state = state, orientation = Orientation.Horizontal) + .size(squareSize) + .background(Color.Blue, RoundedCornerShape(8.dp)) + ) + } + } +} + +private enum class DragValue { Start, Center, End } + + +@Preview +@Composable +private fun PreviewSwipeScroll() { + SwipeScroll_Screen() +} \ No newline at end of file diff --git a/compose/src/main/java/org/zhiwei/compose/screen/layout_state/CustomModifier.kt b/compose/src/main/java/org/zhiwei/compose/screen/layout_state/CustomModifier.kt index f6e70ae..e92601c 100644 --- a/compose/src/main/java/org/zhiwei/compose/screen/layout_state/CustomModifier.kt +++ b/compose/src/main/java/org/zhiwei/compose/screen/layout_state/CustomModifier.kt @@ -172,6 +172,7 @@ private fun UI_CustomModifier() { .nonComposedBackground(160.dp, 30.dp) .width(150.dp) ) { + //注意⚠️:compose的好多组件可能会有自己作用域内的扩展函数,比如Box内就有Modifier的matchParentSize Text(text = "重组Recomposed:${counter.intValue}", color = Color.White) } Box(