11
Nov
2021
Floating Action Button in SwiftUI
Reading time: 1 min
This recipe shows how to implement a floating action button (FAB) in SwiftUI. This is a simple component, common in Android apps, that sits in the bottom-right corner of the screen, floating above the rest of the content.
The end result looks like this:
The recipe goes as follows:
- The FAB is implemented as a
ViewModifier
to allow for easy attachment to any content view. ViewModifier
's content is wrapped in aZStack
alongside the button, allowing it to be on top of the content.- Use a
GeometryReader
to position the button at the bottom-right corner of the screen.
struct FloatingActionButton<ImageView: View>: ViewModifier {
let color: Color // background color of the FAB
let image: ImageView // image shown in the FAB
let action: () -> Void
private let size: CGFloat = 60 // size of the FAB circle
private let margin: CGFloat = 15 // distance from screen edges
func body(content: Content) -> some View {
GeometryReader { geo in
ZStack {
Color.clear // allows the ZStack to fill the entire screen
content
button(geo)
}
}
}
@ViewBuilder private func button(_ geo: GeometryProxy) -> some View {
image
.imageScale(.large)
.frame(width: size, height: size)
.background(Circle().fill(color))
.shadow(color: .gray, radius: 2, x: 1, y: 1)
.onTapGesture(perform: action)
.offset(x: (geo.size.width - size) / 2 - margin,
y: (geo.size.height - size) / 2 - margin)
}
}
Lastly, add this helpful extension:
extension View {
func floatingActionButton<ImageView: View>(
color: Color,
image: ImageView,
action: @escaping () -> Void) -> some View {
self.modifier(FloatingActionButton(color: color,
image: image,
action: action))
}
}
Then, you can use it like this:
private struct FABTest: View {
@State private var noRows = 9
var body: some View {
List(Array(1...noRows), id: \.self) { index in
Text("Row \(index)")
}
.floatingActionButton(color: .blue,
image: Image(systemName: "plus")
.foregroundColor(.white)) {
noRows += 1
}
}
}