【SwiftUI】Twitterのカテゴリータブを作成する

# はじめに
TwitterのカテゴリータブをSwiftUIでマネして作ってみました。

# カテゴリータブどこ？
カテゴリータブって勝手に呼んでるだけです
正式名は知りません
![IMG_2825.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/4bae84d0-7a25-0ce2-ce33-6967af0b0fb5.jpeg)

# 完成形
![Simulator Screen Recording - iPhone 14 Pro - 2023-05-07 at 22.37.21.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/93b73898-65e3-7667-966f-adddd913ba4e.gif)

# 実装
```swift
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))
    }
}
```

# 使い方
```swift
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)
    }
}
```

# おわり
いい感じに作ることができました

# 参考記事
https://hack.nikkei.com/blog/advent20201201/