This is a Compose Multiplatform library that allows you to easily implement a "Google Photos"-style multi-selection in your Compose apps.
You can run the demo at demo.dragselectcompose.com and view the KDocs at docs.dragselectcompose.com
This library is written for Compose Multiplatform, and can be used on the following platforms:
- Android
- iOS
- JVM (Desktop)
- JavaScript/wasm (Browser)
This library was inspired by this article and the gist.
As well as the drag-select-recyclerview library.
You can add this library to your project using Gradle.
To add to a single platform like Android, add the dependency to your app level build.gradle.kts
file:
dependencies {
// Includes the core functionality along with all of the optional modules
implementation("com.dragselectcompose:dragselect:2.3.2")
// Or use the modules you want
// Core functionality
implementation("com.dragselectcompose:core:2.3.2")
// Optional extensions for adding semantics and toggle Modifiers to Grid items
implementation("com.dragselectcompose:extensions:2.3.2")
// Optional wrappers around LazyGrid that implement the selection UI for you
implementation("com.dragselectcompose:grid:2.3.2")
}
To add to a multiplatform project, add the dependency to the common source-set:
kotlin {
sourceSets {
commonMain {
dependencies {
// Includes the core functionality along with all of the optional modules
implementation("com.dragselectcompose:dragselect:2.3.2")
// Or use the modules you want
// Core functionality
implementation("com.dragselectcompose:core:2.3.2")
// Optional extensions for adding semantics and toggle Modifiers to Grid items
implementation("com.dragselectcompose:extensions:2.3.2")
// Optional wrappers around LazyGrid that implement the selection UI for you
implementation("com.dragselectcompose:grid:2.3.2")
}
}
}
}
For the supported platforms, see the badges at the top of the README.
[versions]
dragselectcompose = "2.3.2"
[libraries]
dragselect = { module = "com.dragselectcompose:dragselect", version.ref = "dragselectcompose" }
dragselect-core = { module = "com.dragselectcompose:core", version.ref = "dragselectcompose" }
dragselect-extensions = { module = "com.dragselectcompose:extensions", version.ref = "dragselectcompose" }
dragselect-grid = { module = "com.dragselectcompose:grid", version.ref = "dragselectcompose" }
The :core
artifact provides a Modifier
extension for adding a drag-to-select functionality to
your LazyGrid
:
fun <Item> Modifier.gridDragSelect(
items: List<Item>,
state: DragSelectState<Item>,
enableAutoScroll: Boolean = true,
autoScrollThreshold: Float? = null,
enableHaptics: Boolean = true,
hapticFeedback: HapticFeedback? = null,
): Modifier
It provides the following functionality:
- Adds a long-press drag gesture to select items.
- Maintains a list of selected items.
- Expose a
inSelectionMode: Boolean
which you can use to display a unselected state. - If
enableAutoScroll
istrue
then the list will start to scroll when reaching the top or bottom of the list. - Will trigger a "long-press" haptics if
enableHaptics
istrue
.
Note: By default selected items will be compared using an equality check. If your item is not
a data class
you must implement equals
and hashCode
for your item. Or you can pass a lambda
to rememberDragSelectState
to compare your items:
val dragSelectState = rememberDragSelectState<Foo>(compareSelector = { it.someProperty })
You can then use DragSelectState
to render your list of items:
data class Model(
val id: Int,
val title: String,
val imageUrl: String,
)
@Composeable
fun MyGrid(models: List<Model>) {
val dragSelectState = rememberDragSelectState<Model>()
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 128.dp),
state = dragSelectState.lazyGridState,
verticalArrangement = Arrangement.spacedBy(3.dp),
horizontalArrangement = Arrangement.spacedBy(3.dp),
modifier = Modifier.gridDragSelect(
items = models,
state = dragSelectState,
),
) {
items(models, key = { it.id }) { model ->
val isSelected by remember { derivedStateOf { dragSelectState.isSelected(model) } }
val inSelectionMode = dragSelectState.inSelectionMode
// Define your Model Composeable and use `isSelected` or `inSelectionMode`
}
}
}
You can see a full basic example
in BasicDragSelectPhotoGrid
.
Included in the :dragselectcompose
and :extensions
artifact are a couple extensions on Modifer
to easily add support for accessibility semantics and toggling selection while the Grid is in
selection mode.
Modifier.dragSelectSemantics()
- Adds a long click semantics to the modifier for accessibility.
Modifier.dragSelectToggleable()
- Allows you to toggle the item when the Grid is in Selection Mode.
Modifier.dragSelectToggleableItem()
- Combines the above two extensions.
@Composeable
fun MyGrid(models: List<Model>) {
val dragSelectState = rememberDragSelectState<Model>()
LazyVerticalGrid(
// ...
) {
items(models, key = { it.id }) { model ->
// Add semantics and toggleable modifiers
MyItemContent(
item = model,
modifier = Modifier.dragSelectToggleable(
state = dragSelectState,
item = model,
),
)
}
}
}
You can see a full extensions example
in ExtensionsDragSelectPhotoGrid
.
Included in the :grid
artifact is a "all-inclusive" drag-select experience. It includes wrappers
around LazyHorizontalGrid
and LazyVerticalGrid
that takes care of adding
the Modifier.gridDragSelect
.
When using LazyDragSelectVerticalGrid
or LazyDragSelectHorizontalGrid
the content()
is scoped
to a custom scope that provides a helper composable for handling the selection indicator, and
animating the padding.
Here is a quick example:
@Composeable
fun MyGrid(models: List<Model>) {
val dragSelectState = rememberDragSelectState<Model>()
LazyDragSelectVerticalGrid(
columns = GridCells.Adaptive(minSize = 128.dp),
items = models,
state = dragSelectState,
) {
items(key = { it.id }) { model ->
SelectableItem(item = model) {
// Your Composeable for your item
}
}
}
}
Now your item will have an animated padding and clipped shape when selected. As well as displaying indicator icons when the grid is in selection mode, and the item is selected or not.
See the documentation for LazyDragSelectVerticalGrid
and SelectableItem
for all the options you
can customize.
You can see a full example
in LazyDragSelectPhotoGrid
To run a demo for the library you can look inside of /demo
to see a standard Android application,
and a Compose Multiplatform application.
A demo app is included in the :demo:android
module, run it by following these steps:
git clone git@github.com:jordond/drag-select-compose.git drag-select-compose
cd drag-select-compose
./gradlew assembleRelease
Then install the demo/android/build/outputs/apk/release/demo-release.apk
file on your device.
The demo is inside of :demo:kmm
module. In order to run it you should have the latest version of
Android studio installed.
Check out the README for more information.
See LICENSE