Skip to content

Instantly share code, notes, and snippets.

@Codelaby
Last active April 13, 2025 10:18
Show Gist options
  • Save Codelaby/8fbbf50ef965efbb0fa36ff7d6df05d2 to your computer and use it in GitHub Desktop.
Save Codelaby/8fbbf50ef965efbb0fa36ff7d6df05d2 to your computer and use it in GitHub Desktop.
Expandable Floating Action Button
import SwiftUI
// MARK: Expandable Floating Action Button
struct ExpandableFAB<Content: View>: View {
@Binding var isPresented: Bool
@ViewBuilder var content: Content
var body: some View {
VStack {
// Sub FABs
Group(subviews: content) { collection in
ForEach(Array(collection.enumerated()), id: \.element.id) { index, subview in
subview
.scaleEffect(isPresented ? 1 : 0.1)
.opacity(isPresented ? 1.0 : 0.0)
.animation(
.snappy
.delay(isPresented ? Double(collection.count - index) * 0.1 : Double(index) * 0.1),
value: isPresented
)
}
}
// FAB
Button("FAB", systemImage: "plus") {
isPresented.toggle()
}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.labelStyle(.iconOnly)
.clipShape(.circle)
.rotationEffect(.degrees(isPresented ? 45 : 0))
.animation(.spring, value: isPresented)
.shadow(radius: 5) }
}
}
// MARK: Sub FAB Style
struct SubFABStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.imageScale(.small)
.labelStyle(.iconOnly)
.padding(10)
.background(
Circle()
.fill(Color.accentColor)
.opacity(configuration.isPressed ? 0.8 : 1.0)
)
}
}
// MARK: Playground
#Preview("Expand top") {
@Previewable @State var isExpanded = false
NavigationStack {
List(0..<100) { i in
Text("Item \(i)")
}
.navigationTitle("Expandable FAB")
}
.overlay(alignment: .bottomTrailing) { // FAB placement
ExpandableFAB(isPresented: $isExpanded) {
Button("edit", systemImage: "pencil") {
isExpanded = false
print("action prencil")
}
.buttonStyle(SubFABStyle())
Button("camera", systemImage: "camera") {
isExpanded = false
print("action camera")
}
.buttonStyle(SubFABStyle())
Button("trash", systemImage: "trash") {
isExpanded = false
print("action trash")
}
.buttonStyle(SubFABStyle())
}
.accentColor(.black)
.foregroundStyle(.white)
//.padding(8)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment