It's unclear how the paneExpansionDragHandle
can be applied.
The code documentation says only this:
paneExpansionDragHandle
- provide a custom pane expansion drag handle to allow users to resize panes and change the pane expansion state by dragging. This is null by default, which renders no drag handle. Even there's no drag handle, you can still change pane size directly via modifying paneExpansionState.
The web documentation mentions nothing about that at all.
I tried to use of paneExpansionDragHandle
and paneExpansionState
to make a custom drag handle, but it was inconvenient. How can I achieve this?
The ListDetailPaneScaffold
Composable is part of the material3/adaptive
library. You can find useful documentation and samples there.
You must use the latest material3
dependency to your build.gradle
file to get the predefined VerticalDragHandle
Composable:
implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")
//...
implementation("androidx.compose.material3:material3:1.4.0-alpha04") // VerticalDragHandle
You then can use the paneExpansionDragHandle
like this:
paneExpansionDragHandle = { state ->
val interactionSource = remember { MutableInteractionSource() }
VerticalDragHandle(
modifier = Modifier.paneExpansionDraggable(
state,
LocalMinimumInteractiveComponentSize.current,
interactionSource
),
interactionSource = interactionSource
)
}
Output:
If you want the drag position to snap to predefined anchors, you can also pass anchors in the paneExpansionState
:
paneExpansionState =
rememberPaneExpansionState(
keyProvider = scaffoldNavigator.scaffoldValue,
anchors = listOf(
PaneExpansionAnchor.Proportion(0.25f),
PaneExpansionAnchor.Proportion(0.5f),
PaneExpansionAnchor.Proportion(0.75f),
)
),
Output:
Code Sample
@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3Api::class)
@Composable
fun SampleListDetailPaneScaffoldFull() {
val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator()
val coroutineScope = rememberCoroutineScope()
ListDetailPaneScaffold(
directive = scaffoldNavigator.scaffoldDirective,
value = scaffoldNavigator.scaffoldValue,
listPane = {
AnimatedPane(
modifier = Modifier.preferredWidth(200.dp),
) {
Surface(
color = MaterialTheme.colorScheme.secondary,
onClick = {
coroutineScope.launch {
scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
}
}
) {
Text("List")
}
}
},
detailPane = {
AnimatedPane(modifier = Modifier) {
Surface(
color = MaterialTheme.colorScheme.primary,
) {
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
Text("Detail")
Row(
modifier = Modifier.fillMaxWidth().padding(horizontal = 4.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Surface(
onClick = {
coroutineScope.launch { scaffoldNavigator.navigateBack() }
},
modifier = Modifier.weight(0.5f).fillMaxHeight(),
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.8f)
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Previous")
}
}
VerticalDivider()
Surface(
onClick = {
coroutineScope.launch {
scaffoldNavigator.navigateTo(
ListDetailPaneScaffoldRole.Extra
)
}
},
modifier = Modifier.weight(0.5f).fillMaxHeight(),
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f)
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Next")
}
}
}
}
}
}
},
extraPane = {
AnimatedPane(modifier = Modifier.fillMaxSize()) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.tertiary,
onClick = { coroutineScope.launch { scaffoldNavigator.navigateBack() } }
) {
Text("Extra")
}
}
},
paneExpansionState =
rememberPaneExpansionState(
keyProvider = scaffoldNavigator.scaffoldValue,
anchors = listOf(
PaneExpansionAnchor.Proportion(0.25f),
PaneExpansionAnchor.Proportion(0.5f),
PaneExpansionAnchor.Proportion(0.75f),
)
),
paneExpansionDragHandle = { state ->
val interactionSource = remember { MutableInteractionSource() }
VerticalDragHandle(
modifier =
Modifier.paneExpansionDraggable(
state,
LocalMinimumInteractiveComponentSize.current,
interactionSource
),
interactionSource = interactionSource
)
}
)
}