{"id":14971523,"url":"https://github.com/robbendebiene/freestyle_speed_dial","last_synced_at":"2025-10-26T16:30:44.285Z","repository":{"id":45808465,"uuid":"513174932","full_name":"Robbendebiene/freestyle_speed_dial","owner":"Robbendebiene","description":"A lightweight yet powerful speed dial widget for Flutter, offering full control over the appearance, layout and animations of the speed dial.","archived":false,"fork":false,"pushed_at":"2024-04-05T11:25:53.000Z","size":524,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-31T21:11:29.305Z","etag":null,"topics":["flutter","flutter-widget","speed-dial"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/freestyle_speed_dial","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Robbendebiene.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-12T14:27:38.000Z","updated_at":"2024-11-21T23:39:10.000Z","dependencies_parsed_at":"2024-04-05T11:36:41.572Z","dependency_job_id":"a9d1efd7-b9bc-4f9c-b211-2e5ad7397f57","html_url":"https://github.com/Robbendebiene/freestyle_speed_dial","commit_stats":{"total_commits":16,"total_committers":2,"mean_commits":8.0,"dds":0.4375,"last_synced_commit":"61126b05feeb5e9f5e60ff571540b54065d784d5"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Robbendebiene%2Ffreestyle_speed_dial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Robbendebiene%2Ffreestyle_speed_dial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Robbendebiene%2Ffreestyle_speed_dial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Robbendebiene%2Ffreestyle_speed_dial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Robbendebiene","download_url":"https://codeload.github.com/Robbendebiene/freestyle_speed_dial/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238366704,"owners_count":19460170,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flutter","flutter-widget","speed-dial"],"created_at":"2024-09-24T13:45:19.617Z","updated_at":"2025-10-26T16:30:43.934Z","avatar_url":"https://github.com/Robbendebiene.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"This package provides a single lightweight widget called `SpeedDialBuilder` which allows you to build custom speed dial buttons of all kinds of styles.\n\nIt offers full control over the appearance, layout and animations of the sub-buttons and secondary widgets like button labels.\n\n## Examples\n\nTry the **[live demo](https://robbendebiene.github.io/freestyle_speed_dial/)** or run the example project to see some example layouts and animations.\n\n[\u003cimg src=\"https://raw.githubusercontent.com/Robbendebiene/freestyle_speed_dial/master/resources/examples.png\" /\u003e](https://robbendebiene.github.io/freestyle_speed_dial/)\n\n\n## Usage\n\n### Building the main button\n\nThe starting point of every speed dial button is the main toggle button. Use the `buttonBuilder` to create your own custom toggle button. You can use any combination of widgets there. The only important thing is, that one of the widgets must call the `controller.toggle` function provided by the builder on your desired user interaction.\nTo reflect the state of the speed dial you can alter your widget based on the `controller.isActive`, `controller.status` or `controller.animation` parameter using a transition widget or something like an [AnimatedBuilder](https://api.flutter.dev/flutter/widgets/AnimatedBuilder-class.html). Either listen to the `controller` for status changes or to the `controller.animation` to animate together with the speed dial.\n\nBasic example code:\n\n\n```dart\nSpeedDialBuilder(\n  ...\n  buttonBuilder: (context, controller) =\u003e FloatingActionButton(\n    onPressed: controller.toggle,\n    child: ListenableBuilder(\n      listenable: controller,\n      builder: (BuildContext context, Widget? child) {\n        return Icon( controller.isActive ? Icons.close : Icons.add );\n      }\n    )\n  )\n)\n```\n\n### Adding items and creating sub-buttons\n\nThe items of the speed dial must be passed to the `items` property. There you have the option to either directly pass your widgets or any other data type like a custom container class. The passed items will be available in the `itemBuilder` where you can further specify their appearance, layout and animation.\n\nFor now lets focus on a simple example where we directly pass two items as small `FloatingActionButton` widgets.\n\n```dart\nSpeedDialBuilder(\n  ...\n  items: [\n    FloatingActionButton.small(\n      onPressed: () {},\n      child: const Icon(Icons.hub),\n    ),\n    FloatingActionButton.small(\n      onPressed: () {},\n      child: const Icon(Icons.file_download),\n    )\n  ]\n)\n```\n\nIn the `itemBuilder` we position our items vertically using the supplied item index and the `FractionalTranslation` widget.\n\nAdditionally we wrap every item in a `ScaleTransition` and pass it the provided `animation` object in order to get a nice in and out transition for every item. You can further control the animation with the `animationOverlap`, `reverse`, `duration`, `reverseDuration`, `curve` and `reverseCurve` properties of the `SpeedDialBuilder`.\n\n\n```dart\nSpeedDialBuilder(\n  ...\n  buttonAnchor: Alignment.topCenter,\n  itemAnchor: Alignment.bottomCenter,\n  itemBuilder: (context, Widget item, i, animation, controller) =\u003e FractionalTranslation(\n    translation: Offset(0, -i.toDouble()),\n    child: ScaleTransition(\n      scale: animation,\n      child: item\n    )\n  )\n)\n```\n\nYou may have noticed that two additional properties `buttonAnchor` and `itemAnchor` slipped in. These only control the initial item position before they get translated in the `itemBuilder`. In this case they are placed right above the main button.\nThink of it as defining two points, one on the main button that is fixed and one for every item. Both points are then brought together by repositioning the item.\n\n### Complete example code\n\n```dart\nSpeedDialBuilder(\n  buttonAnchor: Alignment.topCenter,\n  itemAnchor: Alignment.bottomCenter,\n  buttonBuilder: (context, controller) =\u003e FloatingActionButton(\n    onPressed: controller.toggle,\n    child: ListenableBuilder(\n      listenable: controller,\n      builder: (BuildContext context, Widget? child) {\n        return Icon( controller.isActive ? Icons.close : Icons.add );\n      }\n    )\n  ),\n  itemBuilder: (context, Widget item, i, animation, controller) =\u003e FractionalTranslation(\n    translation: Offset(0, -i.toDouble()),\n    child: ScaleTransition(\n      scale: animation,\n      child: item\n    )\n  ),\n  items: [\n    FloatingActionButton.small(\n      onPressed: () {},\n      child: const Icon(Icons.hub),\n    ),\n    FloatingActionButton.small(\n      onPressed: () {},\n      child: const Icon(Icons.file_download),\n    )\n  ]\n)\n```\n\n### Display labels beneath the items\n\nTo freely display labels beneath every item you can use the `secondaryItemBuilder`. In this case you need to pass data objects describing your buttons and labels instead of a single widget to the `items` property. The construction of your widgets (buttons and labels) should then be performed inside the builder methods.\nAlternatively you can also directly include the label in the `itemBuilder` for example using a row. However this approach might make aligning the items a bit harder.\n\nThe below example uses the `secondaryItemBuilder` in combination with Flutters [CompositedTransformTarget](https://api.flutter.dev/flutter/widgets/CompositedTransformTarget-class.html) and [CompositedTransformFollower](https://api.flutter.dev/flutter/widgets/CompositedTransformFollower-class.html) widgets to show a label beneath every item.\n\n```dart\nSpeedDialBuilder(\n  buttonAnchor: Alignment.topCenter,\n  itemAnchor: Alignment.bottomCenter,\n  buttonBuilder: (context, controller) =\u003e FloatingActionButton(\n    onPressed: controller.toggle,\n    child: ListenableBuilder(\n      listenable: controller,\n      builder: (BuildContext context, Widget? child) {\n        return Icon( controller.isActive ? Icons.close : Icons.add );\n      }\n    )\n  ),\n  itemBuilder: (context, (IconData, String, LayerLink) item, i, animation, controller) {\n    return FractionalTranslation(\n      translation: Offset(0, -i.toDouble()),\n      child: CompositedTransformTarget(\n        link: item.$3,\n        child: ScaleTransition(\n          scale: animation,\n          child: FloatingActionButton.small(\n            onPressed: () {},\n            child: Icon(item.$1),\n          ),\n        )\n      )\n    );\n  },\n  secondaryItemBuilder: (context, (IconData, String, LayerLink) item, i, animation, controller) {\n    return CompositedTransformFollower(\n      link: item.$3,\n      targetAnchor: Alignment.centerRight,\n      followerAnchor: Alignment.centerLeft,\n      child: FadeTransition(\n        opacity: animation,\n        child: Card(\n          margin: const EdgeInsets.only( left: 10 ),\n          child: Padding(\n            padding: const EdgeInsets.all(5),\n            child: Text(item.$2),\n          )\n        )\n      )\n    );\n  },\n  items: [\n    (Icons.hub, 'Hub', LayerLink()),\n    (Icons.track_changes, 'Track', LayerLink())\n  ]\n)\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobbendebiene%2Ffreestyle_speed_dial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobbendebiene%2Ffreestyle_speed_dial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobbendebiene%2Ffreestyle_speed_dial/lists"}