Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import SwiftUI
struct ContentView: View {
var body: some View {
TabBar(items: [
(Image(systemName: "tray"), Text("Inbox")),
(Image(systemName: "archivebox"), Text("Archive")),
(Image(systemName: "doc.text"), Text("Drafts")),
])
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct FirstNonNilPreferenceKey<T>: PreferenceKey {
static var defaultValue: T? { nil }
static func reduce(
value: inout T?,
nextValue: () -> T?
) {
value = value ?? nextValue()
}
}
struct TabBar: View {
@State private var selectedItemIndex: Int = 0
let items: [(image: Image, text: Text)]
var body: some View {
HStack {
ForEach(items.indices, content: tabItem(index:))
}.backgroundPreferenceValue(FirstNonNilPreferenceKey<Anchor<CGRect>>.self) { boundsAnchor in
GeometryReader { proxy in
boundsAnchor.map { anchor in
indicator(
width: proxy[anchor].width,
offset: .init(
width: proxy[anchor].minX,
height: proxy[anchor].height
)
)
}
}
}
}
private func tabItem(index: Int) -> some View {
Button(
action: {
withAnimation(.default) {
self.selectedItemIndex = index
}
},
label: {
VStack {
items[index].image
items[index].text
}
}
)
.accentColor(isSelected(index) ? .accentColor : .primary)
.anchorPreference(
key: FirstNonNilPreferenceKey<Anchor<CGRect>>.self,
value: .bounds,
transform: { anchor in self.isSelected(index) ? .some(anchor) : nil }
)
}
private func isSelected(_ index: Int) -> Bool {
index == selectedItemIndex
}
}
private func indicator(
width: CGFloat,
offset: CGSize
) -> some View {
Rectangle()
.foregroundColor(.accentColor)
.frame(width: width, height: 1)
.offset(offset)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.