所以我正在使用 Jetpack Compose 重写应用程序的 UI。我已经使用常规的 Scaffold 函数实现了一个导航抽屉。开箱即用,这提供了两种打开抽屉的方法:按导航图标或向屏幕末尾拖动。有问题的屏幕是列表项的 LazyColumn。
我稍后在这些列表项上实现了 SwipeToDismiss 模式。滑动关闭工作正常,但不再可能拖动任何地方打开导航抽屉。
在旧的基于视图的系统中,导航抽屉将保留一个小宽度,您可以在其中始终拖动以打开抽屉 - 无论子项是否支持拖动。我不确定如何使用 Compose 实现相同的目标。似乎应该是导航抽屉的工作来处理这个 - 而不是它里面的屏幕。
带有导航抽屉的屏幕:
val coroutineScope = rememberCoroutineScope()
val scaffoldState = rememberScaffoldState(
rememberDrawerState(initialValue = DrawerValue.Closed)
)
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text(screenTitle) },
navigationIcon = {
IconButton(
onClick = {
coroutineScope.launch {
scaffoldState.drawerState.open()
}
}
) {
Icon(
Icons.Default.Menu,
contentDescription = "Drawer toggle button"
)
}
},
actions = {
...
}
)
},
drawerContent = {
// List of stuff
...
},
floatingActionButton = {
...
}
) { padding ->
/// Layout with a LazyColumn with elements having SwipeToDismiss
...
}
并滑动以关闭项目(显示在 LazyColumn 内)
@OptIn(
ExperimentalFoundationApi::class,
ExperimentalMaterialApi::class,
ExperimentalAnimationApi::class
)
@Composable
fun SwipeableFeedItemPreview(
onSwipe: suspend () -> Unit,
onlyUnread: Boolean,
item: FeedListItem,
showThumbnail: Boolean,
imagePainter: @Composable (String) -> Unit,
onMarkAboveAsRead: () -> Unit,
onMarkBelowAsRead: () -> Unit,
onItemClick: () -> Unit
) {
val animatedVisibilityState = remember { MutableTransitionState(true) }
val swipeableState = rememberSwipeableState(initialValue = FeedItemSwipeState.NONE)
// Needs to be set once layout is complete
var itemSize by remember { mutableStateOf(Size(1f, 1f)) }
val anchors = mapOf(
0f to FeedItemSwipeState.NONE,
-itemSize.width to FeedItemSwipeState.LEFT,
itemSize.width to FeedItemSwipeState.RIGHT
)
AnimatedVisibility(
visibleState = animatedVisibilityState,
enter = fadeIn(1f),
exit = shrinkVertically(Alignment.CenterVertically) + fadeOut()
) {
Box(
modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned { layoutCoordinates ->
itemSize = layoutCoordinates.size.toSize()
}
.swipeable(
state = swipeableState,
anchors = anchors,
orientation = Orientation.Horizontal,
thresholds = { _, _ ->
FractionalThreshold(0.25f)
}
)
) {
Box(
contentAlignment = swipeIconAlignment,
modifier = Modifier
.matchParentSize()
.background(color)
.padding(horizontal = 24.dp)
) {
AnimatedVisibility(
visible = swipeableState.targetValue != FeedItemSwipeState.NONE,
enter = fadeIn(),
exit = fadeOut()
) {
Icon(
when (item.unread) {
true -> Icons.Default.VisibilityOff
false -> Icons.Default.Visibility
},
contentDescription = stringResource(id = R.string.toggle_read_status)
)
}
}
FeedItemPreview(
item = item,
showThumbnail = showThumbnail,
imagePainter = imagePainter,
onMarkAboveAsRead = onMarkAboveAsRead,
onMarkBelowAsRead = onMarkBelowAsRead,
onItemClick = onItemClick,
modifier = Modifier
.offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
)
}
}
}