抬头仰望星空,是否能发现自己的渺小。

伪斜杠青年

人们总是混淆了欲望和理想

简单粗暴的写了一个粗糙的 Compose ToolTips

对于用过一段时间的 Compose 开发者来说,Compose 目前在完善性上还有一些差距,比如原生的 ToolTips,当然网上也有很多库用来支持,但我觉得有点大材小用。

毕竟,一个 ToolTips 只需要排列一下,然后一定时间内消失就行,于是自己写一下吧,不考虑边界还是灰常简单的~

主要拆解为四个部分:

一些基础属性定义:

private var basePositionMap = mutableMapOf<String, Offset>()
private var baseSizeMap = mutableMapOf<String, IntSize>()
private var tips by mutableStateOf("")
private var tipsDismissJob: Job? = null

Modifier 修饰符定义,主要是监听手势操作:

@Stable
fun Modifier.toolTips(
    onClick: () -> Unit, desc: String
) = this.then(
    Modifier
        .onGloballyPositioned {
            basePositionMap[desc] = it.positionInRoot()
            baseSizeMap[desc] = it.size
        }
        .pointerInput(Unit) {
            detectTapGestures(onTap = {
                onClick.invoke()
            }, onLongPress = {
                tips = desc
            })
        }
)

ToolTips 控件本身:

@Composable
fun ToolTips(content: @Composable () -> Unit = { DefaultToolTips() }) {
    if (tips.isNotEmpty()) {
        ToolTipsBox(Modifier) {
            content()
        }
    }
    val scope = LocalLifecycleOwner.current.lifecycleScope
    LaunchedEffect(tips) {
        tipsDismissJob?.cancel()
        tipsDismissJob = scope.launch {
            delay(2000)
            if (isActive) {
                tips = ""
            }
        }
    }
}

默认 ToolTips 样式:

@Composable
fun DefaultToolTips() {
    Box(
        modifier = Modifier
            .clip(Shapes2)
            .background(color = colorResource(id = R.color.colorOnContent))
            .padding(horizontal = 8.dp, vertical = 4.dp)
    ) {
        Text(text = tips, fontSize = 12.sp, color = colorResource(id = R.color.colorContent))
    }
}

用于布局 TipsBox 位置:

@Composable
private fun ToolTipsBox(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    val position = basePositionMap[tips] ?: return
    val size = baseSizeMap[tips] ?: return
    val y = with(LocalDensity.current) { position.y + 32.dp.toPx() }
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        val placeables = measurables.map { measurable ->
            measurable.measure(constraints)
        }
        layout(constraints.minWidth, constraints.minHeight) {
            placeables.forEach { placeable ->
                placeable.placeRelative(x = (position.x - placeable.width / 2f + size.width / 2f).toInt(), y = y.toInt())
            }
        }
    }
}

用法:

setContent {
    Box(modifier = Modifier.fillMaxWidth()) {
        val contentDescription = "描述文字"
        Icon(
            modifier = Modifier
                //...
                .toolTips(onClick = {
                    //...
                }, contentDescription)
        )
        ToolTips()
    }
}

至于思路,就是存下了长按控件的位置、大小,然后再根据这个位置布局一下 ToolTips 的位置,最后这个 ToolTips 会在一定时间后消失,就这么简单。

但真用起来,其实问题不少,比如可能超过父布局边界,比如可能需要换个方位,就自行调整或者直接用别人设计的更具备实用性的库吧,毕竟我这就图个轻便~

以上!


本站由以下主机服务商提供服务支持:

0条评论

发表评论