画面上部のボタンをタップすると、画面が左右にスクロールしてViewが切り替わると同時に、バーがボタンの下に移動するUIを作成しました。
ソースコード
import SwiftUI
struct BarPagerView: View {
@State private var selectedTab: Int = 0
let tabs: [TabButtonView] = [
.init(icon: Image(systemName: "music.note"), title: "Music"),
.init(icon: Image(systemName: "film.fill"), title: "Movies"),
.init(icon: Image(systemName: "book.fill"), title: "Books")
]
let views: [AnyView] = [
.init(Text("View 01")),
.init(Text("View 02")),
.init(Text("View 03"))
]
var body: some View {
VStack {
Tabs(tabButtonViews: tabs, selectedTab: $selectedTab)
TabView(selection: self.$selectedTab) {
ForEach(0 ..< views.count, id: \.self) { index in
views[index].background(Color.red).tag(index)
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}
struct TabButtonView: View {
var icon: Image?
var title: String
var body: some View {
HStack {
AnyView(icon)
.foregroundColor(.black)
.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0))
Text(title)
.font(Font.system(size: 18, weight: .semibold))
.foregroundColor(Color.black)
.padding(EdgeInsets(top: 10, leading: 3, bottom: 10, trailing: 15))
}
}
}
struct TabBarView: View {
var selectedBarColor: Color
var tabButtonViews: [TabButtonView]
var cellWidth: CGFloat
@Binding var selectedTab: Int
var body: some View {
HStack(spacing: 0) {
ForEach(0 ..< tabButtonViews.count, id: \.self) { row in
Button(action: {
withAnimation {
selectedTab = row
}
}, label: {
VStack(spacing: 0) {
tabButtonViews[row]
.frame(width: cellWidth, height: 52)
}.fixedSize()
})
.accentColor(selectedBarColor)
.buttonStyle(PlainButtonStyle())
}
}
}
}
struct Tabs: View {
var tabButtonViews: [TabButtonView]
@Binding var selectedTab: Int
var body: some View {
let cellWidth: CGFloat = UIScreen.main.bounds.width / CGFloat(tabButtonViews.count)
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
VStack(spacing: 0) {
TabBarView(selectedBarColor: Color.blue, tabButtonViews: tabButtonViews, cellWidth: cellWidth, selectedTab: $selectedTab)
.onChange(of: selectedTab) { target in
withAnimation {
proxy.scrollTo(target)
}
}
// Bar Indicator
Rectangle()
.fill(Color.blue)
.frame(width: cellWidth, height: 3)
.offset(x: CGFloat(selectedTab - 1) * cellWidth, y: 0)
.animation(.spring(), value: selectedTab)
}
}
}
.onAppear(perform: {
UIScrollView.appearance().bounces = false
})
.frame(height: 55)
.onDisappear(perform: {
UIScrollView.appearance().bounces = true
})
}
}