問題:Jetpack Compose 中使用 Material 包中的控制項,點擊預設會有水波紋效果。如何去除這個點擊水波紋效果呢? 看下 Modifier.clickable 的簽名: fun Modifier.clickable( interactionSource: MutableInterac ...
問題:Jetpack Compose 中使用 Material 包中的控制項,點擊預設會有水波紋效果。如何去除這個點擊水波紋效果呢?
看下 Modifier.clickable 的簽名:
fun Modifier.clickable(
interactionSource: MutableInteractionSource,
indication: Indication?,
enabled: Boolean = true,
onClickLabel: String? = null,
role: Role? = null,
onClick: () -> Unit
)
其實就是 indication
這個參數決定的。
針對局部單個點擊去除水波紋效果,我們只需要將該參數設置為 null
即可。
針對全局如何設置呢? indication
參數預設值是 indication = LocalIndication.current
。顯然這是通過 CompositionLocal 的方式傳遞下來的。那麼我們只需要自己定義一個 Indication,在上層把這個屬性值給替換掉即可。比如需要對整個 Activity 生效,就在該 Activity 的根組合項中替換,如果需要整個應用生效,可以在主題中進行替換。
先看一下預設的 Indication 是如何實現的:
val LocalIndication = staticCompositionLocalOf<Indication> {
DefaultDebugIndication
}
private object DefaultDebugIndication : Indication {
private class DefaultDebugIndicationInstance(
private val isPressed: State<Boolean>,
private val isHovered: State<Boolean>,
private val isFocused: State<Boolean>,
) : IndicationInstance {
override fun ContentDrawScope.drawIndication() {
drawContent()
if (isPressed.value) {
drawRect(color = Color.Black.copy(alpha = 0.3f), size = size)
} else if (isHovered.value || isFocused.value) {
drawRect(color = Color.Black.copy(alpha = 0.1f), size = size)
}
}
}
@Composable
override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
val isPressed = interactionSource.collectIsPressedAsState()
val isHovered = interactionSource.collectIsHoveredAsState()
val isFocused = interactionSource.collectIsFocusedAsState()
return remember(interactionSource) {
DefaultDebugIndicationInstance(isPressed, isHovered, isFocused)
}
}
}
其實在這個文件中已經實現了一個 NoIndication, 只不過是 private 的:
private object NoIndication : Indication {
private object NoIndicationInstance : IndicationInstance {
override fun ContentDrawScope.drawIndication() {
drawContent()
}
}
@Composable
override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
return NoIndicationInstance
}
}
這裡面涉及到了兩個介面:
@Stable
interface Indication {
@Composable
fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance
}
interface IndicationInstance {
fun ContentDrawScope.drawIndication()
}
看起來,邏輯很清晰,自定義一個 Indication 需要兩步:
- 實現IndicationInstance 介面,實現
ContentDrawScope.drawIndication()
方法。並把這個對象返回。看方法名,應該就是繪製點擊效果。預設實現中使用到了 interactionSource ,根據點擊的狀態不同,繪製出不同的效果。 - 實現 Indication 的介面,實現
rememberUpdatedInstance
方法,返回上面的IndicationInstance
類型的對象。
有了理論基礎,我們實操一下,去掉點擊水波紋效果,也分為兩步:
- 定義一個無點擊效果的 Indication。直接把源碼中的那個私有的照抄就行了,讓我們應用可用。
object NoIndication: Indication {
private object NoIndicationInstance: IndicationInstance {
override fun ContentDrawScope.drawIndication() {
drawContent()
}
}
@Composable
override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
return NoIndicationInstance
}
}
- 應用這個 Indication
@Composable
fun CustomTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
...
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = {
CompositionLocalProvider(LocalIndication provides NoIndication) {
content()
}
}
)
}
Done !!!
相信有了這個理論基礎,我們完全可以自定義自己想要的點擊效果了。
作者:SharpCJ 作者博客:http://joy99.cnblogs.com/ 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。