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
)
}
)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With