Convert Figma logo to code with AI

leinardi logoFloatingActionButtonSpeedDial

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)

1,459
140
1,459
45

Top Related Projects

Android Floating Action Button based on Material Design specification

Quick Overview

FloatingActionButtonSpeedDial is an Android library that provides a Floating Action Button Speed Dial implementation. It allows developers to create a main floating action button that expands to reveal multiple action items, similar to the speed dial feature in mobile phones. This library offers a customizable and easy-to-use solution for implementing complex FAB interactions in Android applications.

Pros

  • Easy integration with existing Android projects
  • Highly customizable appearance and behavior
  • Supports both regular and mini FABs
  • Compatible with Material Design guidelines

Cons

  • Limited to Android platform only
  • May require additional setup for complex use cases
  • Potential performance impact with a large number of action items
  • Requires careful consideration of UI/UX design to avoid cluttering the interface

Code Examples

  1. Basic implementation of FloatingActionButtonSpeedDial:
val speedDial: SpeedDialView = findViewById(R.id.speedDial)
speedDial.addActionItem(
    SpeedDialActionItem.Builder(R.id.fab_action1, R.drawable.ic_action1)
        .setLabel("Action 1")
        .create()
)
speedDial.addActionItem(
    SpeedDialActionItem.Builder(R.id.fab_action2, R.drawable.ic_action2)
        .setLabel("Action 2")
        .create()
)
  1. Setting up a click listener for action items:
speedDial.setOnActionSelectedListener { actionItem ->
    when (actionItem.id) {
        R.id.fab_action1 -> {
            // Handle action 1
            true
        }
        R.id.fab_action2 -> {
            // Handle action 2
            true
        }
        else -> false
    }
}
  1. Customizing the appearance of the main FAB:
speedDial.mainFabClosedBackgroundColor = ContextCompat.getColor(this, R.color.colorPrimary)
speedDial.mainFabOpenedBackgroundColor = ContextCompat.getColor(this, R.color.colorAccent)
speedDial.mainFabClosedIconResource = R.drawable.ic_add
speedDial.mainFabOpenedIconResource = R.drawable.ic_close

Getting Started

  1. Add the dependency to your app's build.gradle file:
dependencies {
    implementation 'com.leinardi.android:speed-dial:3.3.0'
}
  1. Add the SpeedDialView to your layout XML:
<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" />
  1. Initialize and configure the SpeedDialView in your Activity or Fragment:
val speedDial: SpeedDialView = findViewById(R.id.speedDial)
speedDial.addActionItem(
    SpeedDialActionItem.Builder(R.id.fab_action1, R.drawable.ic_action1)
        .setLabel("Action 1")
        .create()
)
speedDial.setOnActionSelectedListener { actionItem ->
    // Handle action item selection
    false
}

Competitor Comparisons

Pros of FloatingView

  • Supports system overlay windows, allowing the view to float over other apps
  • Provides smooth animations and physics-based movements
  • Offers more flexibility in terms of content and layout

Cons of FloatingView

  • Less focused on speed dial functionality
  • May require more custom implementation for specific use cases
  • Potentially more complex to set up and configure

Code Comparison

FloatingView:

FloatingViewManager mFloatingViewManager = new FloatingViewManager(this);
mFloatingViewManager.setFixedTrashIconImage(R.drawable.ic_trash_fixed);
mFloatingViewManager.setActionTrashIconImage(R.drawable.ic_trash_action);
mFloatingViewManager.setDisplayMode(FloatingViewManager.DISPLAY_MODE_SHOW_ALWAYS);
mFloatingViewManager.addViewToWindow(inflatedView, options);

FloatingActionButtonSpeedDial:

val speedDialView = findViewById<SpeedDialView>(R.id.speedDial)
speedDialView.addActionItem(
    SpeedDialActionItem.Builder(R.id.fab_action1, R.drawable.ic_action1)
        .setLabel(getString(R.string.action1))
        .create()
)
speedDialView.setOnActionSelectedListener { actionItem ->
    when (actionItem.id) {
        R.id.fab_action1 -> // Handle action 1
    }
    false
}

The code snippets show that FloatingView focuses on creating a floating window manager, while FloatingActionButtonSpeedDial is more specialized for creating speed dial actions with a Floating Action Button.

Android Floating Action Button based on Material Design specification

Pros of FloatingActionButton

  • Simpler implementation for basic FAB functionality
  • Lightweight library with minimal dependencies
  • Easier to customize individual FAB appearance

Cons of FloatingActionButton

  • Limited support for complex FAB animations and transitions
  • Lacks built-in speed dial functionality
  • Fewer options for label positioning and styling

Code Comparison

FloatingActionButton:

FloatingActionButton fab = new FloatingActionButton.Builder(this)
    .setContentView(icon)
    .build();

FloatingActionButtonSpeedDial:

SpeedDialView speedDialView = findViewById(R.id.speedDial);
speedDialView.addActionItem(
    new SpeedDialActionItem.Builder(R.id.fab_action1, R.drawable.ic_action1)
        .setLabel("Action 1")
        .create()
);

The FloatingActionButton library offers a more straightforward approach for creating basic FABs, while FloatingActionButtonSpeedDial provides a more feature-rich solution for implementing speed dial functionality with multiple actions.

FloatingActionButton is better suited for simple FAB implementations, whereas FloatingActionButtonSpeedDial excels in creating complex FAB menus with multiple options and animations.

When choosing between the two, consider the specific requirements of your project, such as the need for speed dial functionality, the desired level of customization, and the complexity of animations required.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Floating Action Button Speed Dial

Maven Central Compose Maven Central View Travis GitHub license Stars

Android library providing an implementation of the Material Design Floating Action Button Speed Dial for both classic View and Compose.

Features

  • MinSdk 14 for Classic View and 21 for Compose
  • Highly customizable (label, icon, ripple, fab and label background colors, themes support)
  • Same animations as in Inbox by Gmail
  • Option to have different icons for open/close state
  • Optional overlay/touch guard layout
  • Support for bottom, left and right menu expansion (left and right have no labels)
  • Out-of-the box support for Snackbar behavior
  • Optional support for RecyclerView and NestedScrollView behavior
  • Support for VectorDrawable
  • Easy to use
  • 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 Maven Central Compose Maven Central View):

// 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

Get it on the Play Store

Screenshots

API 27, API 16, bottom and left expansion

FAQ

How can I create a new resource ID, required by the SpeedDialActionItem.Builder?

It can be done in XML using the <item type="id" />:


<resources>
    <item name="fab_action1" type="id" />
    <item name="fab_action2" type="id" />
    <item name="fab_action3" type="id" />
    <item name="fab_action4" type="id" />
</resources>

How can I change the maximum length of the label?

You can set a different value for the max length of the label overriding sd_label_max_width:

<dimen name="sd_label_max_width">240dp</dimen>

More info here.

How can I change the color of the overlay / touch guard layout?

The color of the SpeedDialOverlayLayout can be changed simply using the android:background attribute or, programmatically, using the equivalent setter like any other view.

How can I prevent the overlay / touch guard layout from going over the Toolbar inside a CoordinatorLayout?

It can be done using the attribute app:layout_behavior="@string/appbar_scrolling_view_behavior":


<com.leinardi.android.speeddial.SpeedDialOverlayLayout android:id="@+id/overlay" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" />

Changelog

See the CHANGELOG.md

Credits

This project is based on floating-action-menu by ArthurGhazaryan.

Licenses

Copyright 2021 Roberto Leinardi.

Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements.  See the NOTICE file distributed with this work for
additional information regarding copyright ownership.  The ASF licenses this
file to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License.  You may obtain a copy of
the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
License for the specific language governing permissions and limitations under
the License.