UI 在 Jetpack Compose 中测试时未在 Box 上调用 LaunchedEffect

LaunchedEffect not called on Box while UI testing in Jetpack Compose

我是 运行 LaunchedEffect 的简单测试:

@Test
fun testSomeState() {
    composeTestRule.setContent {
        SomeComposable {
            println("click $it")
        }
    }
    composeTestRule.onNodeWithTag("Zivi")
        .performClick()
        .assertExists()
}

@Composable
fun SomeComposable(onClick: (Int) -> Unit) {
    var someState by remember { mutableStateOf(0) }

    Button(modifier = Modifier.testTag("Zivi").pointerInteropFilter {
        someState = when (it.action) {
            MotionEvent.ACTION_DOWN -> { 1 }
            MotionEvent.ACTION_UP -> { 2 }
            else -> { someState  }
        }
        true

    }, onClick = { }) {}

    LaunchedEffect(someState) {
        println("LaunchedEffect someState $someState") // prints "LaunchedEffect someState 0" 
                                                       // and then "LaunchedEffect someState 2"
        if (someState == 2) { onClick(someState) }
    }
}

这很有效,但是,如果我将 Button 更改为 Box,如下所示:

@Composable
fun SomeComposable(onClick: (Int) -> Unit) {
    var someState by remember { mutableStateOf(0) }

    Box(modifier = Modifier.testTag("Zivi").pointerInteropFilter {
        someState = when (it.action) {
            MotionEvent.ACTION_DOWN -> { 1 }
            MotionEvent.ACTION_UP -> { 2 }
            else -> { someState  }
        }
        true

    }) {}

    LaunchedEffect(someState) {
        println("LaunchedEffect someState $someState") // prints "LaunchedEffect someState 0"
        if (someState == 2) { onClick(someState) }
    }
}

然后在performClick上没有调用LaunchedEffect,谁能帮我理解为什么?

默认情况下可组合框没有任何大小,因此从技术上讲,当用户点击屏幕的任何部分时,事件不会被 Box 消耗。

您可以通过向框添加 background(color = Color.Green) 修饰符来验证这一点,并观察到屏幕上没有任何部分像预期的那样变成绿色。

您可以通过为 Box.

设置 size 修饰符来解决此问题

您可以将您的框实现更改为此,它应该可以工作。我在这里使用fillMaxSize

@Composable
fun SomeComposable(onClick: (Int) -> Unit) {
    var someState by remember { mutableStateOf(0) }

    Box(modifier = Modifier
        .fillMaxSize()
        .testTag("Zivi")
        .pointerInteropFilter {
            someState = when (it.action) {
                MotionEvent.ACTION_DOWN -> {
                    1
                }
                MotionEvent.ACTION_UP -> {
                    2
                }
                else -> {
                    someState
                }
            }
            true

        }) {}

    LaunchedEffect(someState) {
        println("LaunchedEffect someState $someState") // prints "LaunchedEffect someState 0"
        // and then "LaunchedEffect someState 2"
        if (someState == 2) {
            onClick(someState)
        }
    }
}