FloatingActionButtonSpeedDial
A Floating Action Button Speed Dial implementation for Android that follows the Material Design specification (https://material.io/components/buttons-floating-action-button#types-of-transitions)
Install / Use
/learn @leinardi/FloatingActionButtonSpeedDialREADME
Floating Action Button Speed Dial
<img src="/art/demo_1.gif" width="290" align="right" hspace="0" />Android library providing an implementation of the Material Design Floating Action Button Speed Dial for both classic View and Compose.
Features
- [x] MinSdk 14 for Classic View and 21 for Compose
- [x] Highly customizable (label, icon, ripple, fab and label background colors, themes support)
- [x] Same animations as in Inbox by Gmail
- [x] Option to have different icons for open/close state
- [x] Optional overlay/touch guard layout
- [x] Support for bottom, left and right menu expansion (left and right have no labels)
- [x] Out-of-the box support for Snackbar behavior
- [x] Optional support for
RecyclerViewandNestedScrollViewbehavior - [x] Support for VectorDrawable
- [x] Easy to use
- [x] Compose ready!
How to use
Gradle setup
Official releases
The library is available on Jcenter so no additional repository is required.
Dependencies entry (latest version on Maven Central
):
// Compose only
implementation "com.leinardi.android:speed-dial.compose:1.0.0-alpha04"
// Classic View only
implementation "com.leinardi.android:speed-dial:3.3.0"
Snapshots (development branch)
You can use JitPack to test the latest master (remember that master is the development branch and can be unstable or completely broken).
Add the JitPack repository to your build file:
maven { url 'https://jitpack.io' }
Add the dependency
implementation 'com.github.leinardi:FloatingActionButtonSpeedDial:master-SNAPSHOT'
Basic use for Compose
SpeedDial
Add the SpeedDial() Composable to the floatingActionButton of your Scaffold:
var speedDialState by rememberSaveable { mutableStateOf(SpeedDialState.Collapsed) }
var overlayVisible: Boolean by rememberSaveable { mutableStateOf(speedDialState.isExpanded()) }
Scaffold(
floatingActionButton = {
SpeedDial(
state = speedDialState,
onFabClick = { expanded ->
overlayVisible = !expanded
speedDialState = SpeedDialState(!expanded)
},
) {
}
}
) {
SpeedDialOverlay(
visible = overlayVisible,
onClick = {
overlayVisible = false
speedDialState = speedDialState.toggle()
},
)
}
Action items
Add the FabWithLabel items to the SpeedDial:
SpeedDial(
state = speedDialState,
onFabClick = { expanded ->
overlayVisible = !expanded
speedDialState = SpeedDialState(!expanded)
},
) {
item {
FabWithLabel(
onClick = { showToast(context, "Item 1 clicked!") },
labelContent = { Text(text = "Item 1") },
) {
Icon(Icons.Default.Share, null)
}
}
item {
FabWithLabel(
onClick = { showToast(context, "Item 2 clicked!") },
labelContent = { Text(text = "Item 2") },
) {
Icon(Icons.Default.Share, null)
}
}
}
Basic use for Classic View
SpeedDialView
Add the SpeedDialView to your layout:
<com.leinardi.android.speeddial.SpeedDialView android:id="@+id/speedDial" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" app:sdMainFabClosedSrc="@drawable/ic_add_white_24dp" />
Action items
Add the items to the SpeedDialView:
val speedDialView = findViewById<SpeedDialView>(R.id.speedDial)
speedDialView.addActionItem(
SpeedDialActionItem.Builder(R.id.fab_no_label, R.drawable.ic_link_white_24dp)
.create()
)
If the color customization is not requested, it is also possible to inflate the Action items form a Menu Resource:
speedDialView.inflate(R.menu.menu_speed_dial)
Only the attributes android:id, android:icon and android:title are supported.
Click listeners
Add the click listeners:
speedDialView.setOnActionSelectedListener(SpeedDialView.OnActionSelectedListener { actionItem ->
when (actionItem.id) {
R.id.fab_no_label -> {
showToast("No label action clicked!\nClosing with animation")
speedDialView.close() // To close the Speed Dial with animation
return@OnActionSelectedListener true // false will close it without animation
}
}
false
})
Optional steps
Add the main action click listener
speedDialView.setOnChangeListener(object : SpeedDialView.OnChangeListener {
override fun onMainActionSelected(): Boolean {
showToast("Main action clicked!")
return false // True to keep the Speed Dial open
}
override fun onToggleChanged(isOpen: Boolean) {
Log.d(TAG, "Speed dial toggle state changed. Open = $isOpen")
}
})
Customizing the items
The SpeedDialActionItem.Builder provides several setters to customize the aspect of one item:
speedDialView.addActionItem(
SpeedDialActionItem.Builder(R.id.fab_custom_color, drawable)
.setFabBackgroundColor(ResourcesCompat.getColor(resources, R.color.material_white_1000, getTheme()))
.setFabImageTintColor(ResourcesCompat.getColor(resources, R.color.inbox_primary, getTheme()))
.setLabel(getString(R.string.label_custom_color))
.setLabelColor(Color.WHITE)
.setLabelBackgroundColor(ResourcesCompat.getColor(resources, R.color.inbox_primary, getTheme()))
.setLabelClickable(false)
.create()
)
It is also possible to specify a theme to easily change the FAB background and ripple effect color:
speedDialView.addActionItem(
SpeedDialActionItem.Builder(R.id.fab_custom_theme, R.drawable.ic_theme_white_24dp)
.setLabel(getString(R.string.label_custom_theme))
.setTheme(R.style.AppTheme_Purple)
.create()
)
<style name="AppTheme.Purple" parent="AppTheme">
<item name="colorPrimary">@color/material_purple_500</item>
<item name="colorPrimaryDark">@color/material_purple_700</item>
<item name="colorAccent">@color/material_purple_a700</item>
<item name="colorControlHighlight">@color/material_purple_200</item>
</style>
Adding an overlay/touch guard when the menu is open (like Inbox by Gmail)
You simply need to add the SpeedDialOverlayLayout to your layout:
<com.leinardi.android.speeddial.SpeedDialOverlayLayout android:id="@+id/overlay" android:layout_width="match_parent" android:layout_height="match_parent" />
and then provide the instance of that layout to the SpeedDialView:
<com.leinardi.android.speeddial.SpeedDialView android:id="@+id/speedDial" android:layout_width="wrap_content" android:layout_height="wrap_content" app:sdMainFabClosedSrc="@drawable/ic_add_white_24dp" app:sdOverlayLayout="@id/overlay" />
or
val overlayLayout = findViewById<SpeedDialOverlayLayout>(R.id.overlay)
speedDialView.setSpeedDialOverlayLayout(overlayLayout)
Hiding the FAB when scrolling a RecyclerView or a NestedScrollView
Just apply the ScrollingViewSnackbarBehavior to the SpeedDialView. This can be done via XML using the convenience string
resource @string/speeddial_scrolling_view_snackbar_behavior:
<com.leinardi.android.speeddial.SpeedDialView android:id="@+id/speedDial" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_behavior="@string/speeddial_scrolling_view_snackbar_behavior" />
Or programmatically:
val params = speedDialView.layoutParams as CoordinatorLayout.LayoutParams
params.behavior = SpeedDialView.ScrollingViewSnackbarBehavior()
speedDialView.requestLayout()
NB: for the behaviors to work, SpeedDialView needs to be a direct child of CoordinatorLayout
Disabling SnackbarBehavior
Since the SnackbarBehavior is enabled by default and, afaik, it is not possible to remove a Behavior, simply use apply
the SpeedDialView.NoBehavior instead:
val params = speedDialView.layoutParams as CoordinatorLayout.LayoutParams
params.behavior = SpeedDialView.NoBehavior()
speedDialView.requestLayout()
Sample project
A fully working example is available here.
Demo
Video
https://www.youtube.com/watch?v=tWowiF5ElAg
Sample app
Screenshots
API 27, API 16, bottom and left expansion
<img src="/art/screenshot_api_27.png" width="215"/> <img src="/art/screenshot_api_16.png" width="215"/> <img src="/art/screenshot_api_27_top_fab_bottom_expansion.png" width="215"/> <img src="/art/screenshot_api_27_bottom_fab_left
Related Skills
pestel-analysis
Analyze political, economic, social, technological, environmental, and legal forces
orbit-planning
O.R.B.I.T. - strategic project planning before you build. Objective, Requirements, Blueprint, Implementation Roadmap, Track.
next
A beautifully designed, floating Pomodoro timer that respects your workspace.
product-manager-skills
31PM skill for Claude Code, Codex, Cursor, and Windsurf: diagnose SaaS metrics, critique PRDs, plan roadmaps, run discovery, and coach PM career transitions.

