允许应用检测对该元素的点击。
@Composable
fun ClickableSample() {
val count = remember { mutableStateOf(0) }
Text(
text = count.value.toString(),
modifier = Modifier.clickable { count.value += 1 }
)
}
当需要更大灵活性时,提供点按手势检测器。
detectTapGestures( 检测点击手势 |
detectDragGestures( 检测拖动手势:dragAmount.x 和 dragAmount.y 拿到各方向上的拖动距离。 |
Modifier.pointerInput(Unit) {
detectTapGestures(
...
)
}
Modifier.verticalScroll 和 Modifier.horizontalScroll 可以让内容边界大于最大尺寸约束时滚动里面的元素。借助 ScrollState 还可以更改滚动位置或获取当前状态。
@Composable
fun ScrollBoxes() {
val scrollState = rememberScrollState()
LaunchedEffect(Unit) { scrollState.animateScrollTo(100) }
Column(
modifier = Modifier
.background(Color.LightGray)
.size(100.dp)
// .verticalScroll(rememberScrollState()) //使用默认参数
.verticalScroll(scrollState) //一显示就会自动滚动100px
) {
repeat(10) {
Text("Item $it", modifier = Modifier.padding(2.dp))
}
}
}
只检测手势不偏移内容。构造时需要提供一个 consumeScrollDelta( ) 函数,该函数在每个滚动步骤都会调用,以像素为单位,返回所消耗的距离。
@Composable
fun ScrollableSample() {
var offset by remember { mutableStateOf(0f) }
Box(
Modifier
.size(150.dp)
.scrollable(
orientation = Orientation.Vertical,
state = rememberScrollableState { delta ->
//拿到每次滑动的偏移量delta
offset += delta
delta
}
)
.background(Color.LightGray),
contentAlignment = Alignment.Center
) {
Text(offset.toString())
}
}
简单的嵌套滚动无需额外操作,当子元素无法进一步滚动时手势会由父元素处理,手势会自动从子元素传播到父元素。
//父Box嵌套10个子Box,子Box滚动到边界会滚动父Box
@Composable
fun ScrollableSample() {
//设置渐变色方便观察子Box滚动(蓝→黄1000级)
val gradient = Brush.verticalGradient(0f to Color.Blue, 1000f to Color.Yellow)
Box(
modifier = Modifier
.background(Color.LightGray)
.verticalScroll(rememberScrollState())
.padding(32.dp)
) {
Column {
repeat(10) {
Box(
modifier = Modifier
.height(128.dp)
.verticalScroll(rememberScrollState())
) {
Text(
text = "Scroll here",
color = Color.Red,
modifier = Modifier
.border(12.dp, Color.DarkGray)
.background(brush = gradient)
.padding(24.dp)
.height(150.dp)
)
}
}
}
}
}
只检测手势不偏移内容(需要保存状态并在屏幕上表示,例如通过 offset 修饰符移动元素),以像素为单位。
//文字横向拖动
var offsetX by remember { mutableStateOf(0f) }
Text(
modifier = Modifier
.offset { IntOffset(offsetX.roundToInt(), 0) }
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta ->
offsetX += delta
}
),
text = "Drag me!"
)
改为 pointerInput 修饰符使用手势检测。
//父Box中拖动蓝色子Box
@Composable
fun ScrollableSample() {
Box(modifier = Modifier.fillMaxSize()) {
var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }
Box(
Modifier
.offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
.background(Color.Blue)
.size(50.dp)
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
offsetX += dragAmount.x
offsetY += dragAmount.y
}
}
)
}
}
只检测手势不偏移内容(需要保存状态并在屏幕上表示,例如通过 offset 修饰符移动元素)。具有惯性,释放后会朝着锚点呈现动画效果,常见用途是滑动关闭。
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SwipeableSample() {
val squareSize = 48.dp //子Box的大小
val swipeableState = rememberSwipeableState(0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() } //DP转PX
//设置锚点(key是像素,value是索引)
val anchors = mapOf(0f to 0, sizePx to 1)
Box(
modifier = Modifier
.width(96.dp)
.swipeable(
state = swipeableState,
anchors = anchors,
//阈值(超过就会自己滑到底,达不到就会滑回来)
thresholds = { _, _ -> FractionalThreshold(0.3f) },
orientation = Orientation.Horizontal
)
.background(Color.LightGray)
) {
Box(
Modifier
.offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
.size(squareSize)
.background(Color.DarkGray)
)
}
}
只检测手势不转换元素。平移、缩放、旋转。
@Composable
fun TransformableSample() {
var scale by remember { mutableStateOf(1f) } //缩放
var rotation by remember { mutableStateOf(0f) } //旋转
var offset by remember { mutableStateOf(Offset.Zero) } //平移
val state = rememberTransformableState { zoomChange, offsetChange, rotationChange ->
scale *= zoomChange
rotation += rotationChange
offset += offsetChange
}
Box(
Modifier
.graphicsLayer(
scaleX = scale, //等比缩放
scaleY = scale, //等比缩放
rotationZ = rotation,
translationX = offset.x,
translationY = offset.y
)
.transformable(state = state)
.background(Color.Blue)
.fillMaxSize()
)
}