はじめに
TwitterのカテゴリータブをSwiftUIでマネして作ってみました。
カテゴリータブどこ?
カテゴリータブって勝手に呼んでるだけです
正式名は知りません
完成形
実装
import SwiftUI
struct TwitterCategoryTabView<T: View>: View {
@State private var selection = 0
let tabs: [TwitterCategoryTabItem<T>]
var body: some View {
VStack(spacing: 0) {
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
HStack {
ForEach(tabs.indices, id: \.self) { index in
Text(tabs[index].tabLabel)
.font(.headline)
.padding(.all, 10)
.twitterCategoryTabSelectionStyle(isSelected: index == selection)
.tag(index)
.onTapGesture {
withAnimation {
selection = index
}
}
}
}
.onChange(of: selection) { index in
withAnimation {
proxy.scrollTo(index, anchor: .center)
}
}
}
}
Divider()
TabView(selection: $selection) {
ForEach(tabs.indices, id: \.self) { index in
tabs[index].content()
.tag(index)
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}
struct TwitterCategoryTabItem<T>: Identifiable where T: View {
let id = UUID()
let tabLabel: String
let content: () -> T
init(_ tabLabel: String, @ViewBuilder content: @escaping () -> T) {
self.tabLabel = tabLabel
self.content = content
}
}
struct TwitterCategoryTabSelectionStyle: ViewModifier {
let isSelected: Bool
func body(content: Content) -> some View {
ZStack(alignment: .bottom) {
content
.foregroundColor(isSelected ? .primary : .secondary)
if isSelected {
RoundedRectangle(cornerRadius: 3)
.frame(height: 3)
.foregroundColor(Color(red: 35/255, green: 140/255, blue: 216/255))
.padding(.horizontal, 3)
}
}
}
}
extension View {
func twitterCategoryTabSelectionStyle(isSelected: Bool) -> some View {
self.modifier(TwitterCategoryTabSelectionStyle(isSelected: isSelected))
}
}
使い方
import SwiftUI
struct ContentView: View {
var body: some View {
TwitterCategoryTabView(tabs: [
.init("おすすめ", content: {
mockView()
}),
.init("トレンド", content: {
mockView()
}),
.init("ニュース", content: {
mockView()
}),
.init("スポーツ", content: {
mockView()
}),
.init("エンターテイメント", content: {
mockView()
})
])
}
private func mockView() -> some View {
List {
ForEach(0..<10) { index in
Text("トピック: \(index)")
}
}
.listStyle(.plain)
}
}
おわり
いい感じに作ることができました
参考記事