Press "Enter" to skip to content

【SwiftUI】リストにフィルターをかける

セグメントメニューを配置して、メニューごとに表示するリストを変えるサンプルです。今回はフィルター用のViewを作成してみます。

struct Schedule {
    let title: String
    let type: String
}

// 今回使用するサンプルデータ
struct ScheduleList {
    var schedules: [Schedule] = []
    
    init() {
        for num in 1...5 {
            schedules.append(Schedule(title: "予定\(num)", type: ["A", "B", "C"].randomElement()!))
        }
    }
}

// リストにフィルターをかけるView
struct FilteredList<Content: View, Schedule>: View {
    let content: (Schedule) -> Content
    let currentTab: String
    let scheduleList: ScheduleList
    
    init(list: ScheduleList, currentTab: String, @ViewBuilder content: @escaping (Schedule) -> Content) {
        self.scheduleList = list
        self.currentTab = currentTab
        self.content = content
    }
    
    var body: some View {
        VStack {
            // タブで選択されているタイプの予定を抽出します
            let schedules = scheduleList.schedules.filter { $0.type == currentTab }
            
            if schedules.isEmpty {
                Text("予定はありません")
            } else {
                ForEach(schedules, id: \.title) { schedule in
                    self.content(schedule as! Schedule)
                }
            }
        }
    }
}

struct ContentView: View {
    @State var currentTab: String = "B"
    @Namespace var animation
    let scheduleList = ScheduleList()
    
    var body: some View {
        VStack {
            HStack(alignment: .top) {
                let tabs = ["A", "B", "C"]
                ForEach(tabs, id:\.self) { tab in
                    Text(tab)
                        .padding(.vertical,6)
                        .frame(maxWidth: .infinity)
                        .foregroundColor(currentTab == tab ? .white : .black)
                        .background{
                            if currentTab == tab {
                                Capsule()
                                    .fill(.black)
                                    .matchedGeometryEffect(id: "TAB", in: animation)
                            }
                        }
                        .onTapGesture {
                            currentTab = tab
                        }
                }
            }
            .padding()
            
            FilteredList(list: scheduleList, currentTab: currentTab) { (schedule: Schedule) in
                ScheduleView(schedule: schedule)
            }
        }
        .frame(maxHeight: .infinity, alignment: .top)
    }
    
    func ScheduleView(schedule: Schedule) -> some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                Text(schedule.title)
                Text(schedule.type)
            }
        }
        .padding()
    }
}

コメントを残す

メールアドレスが公開されることはありません。