fix: use offset+clipToBounds instead of graphicsLayer alpha for tab keep-alive

Hidden tabs with graphicsLayer{alpha=0f} still intercepted touch events.
Replaced with offset(x=2000.dp) + parent clipToBounds() so hidden composables
are off-screen and cannot capture touches meant for the visible tab.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 12:04:33 +08:00
parent 014437760d
commit 3c90adae6a
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Chat
@@ -21,7 +22,8 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@@ -145,28 +147,29 @@ fun MainScreen(
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.clipToBounds()
.background(MaterialTheme.colorScheme.background),
) {
// Keep all tabs composed to avoid destroying ChatScreen on tab switch.
// Hidden tabs use graphicsLayer { alpha = 0f } — invisible but alive.
// Keep all tabs alive by offsetting hidden ones off-screen.
// clipToBounds ensures they don't intercept touches outside the visible area.
Box(
modifier = Modifier
.fillMaxSize()
.graphicsLayer { alpha = if (selectedTab == 0) 1f else 0f },
.offset(x = if (selectedTab == 0) 0.dp else 2000.dp),
) {
ChatScreen()
}
Box(
modifier = Modifier
.fillMaxSize()
.graphicsLayer { alpha = if (selectedTab == 1) 1f else 0f },
.offset(x = if (selectedTab == 1) 0.dp else 2000.dp),
) {
IoTScreen()
}
Box(
modifier = Modifier
.fillMaxSize()
.graphicsLayer { alpha = if (selectedTab == 2) 1f else 0f },
.offset(x = if (selectedTab == 2) 0.dp else 2000.dp),
) {
ProfileScreen(
onNavigateToSettings = { navController.navigate(Routes.SETTINGS) },