Skip to content

Instantly share code, notes, and snippets.

@YusukeHosonuma
Last active December 12, 2022 16:49
Show Gist options
  • Save YusukeHosonuma/7bcb6afa796e076164569e22fa809e68 to your computer and use it in GitHub Desktop.
Save YusukeHosonuma/7bcb6afa796e076164569e22fa809e68 to your computer and use it in GitHub Desktop.
Before: [SwiftUI] タブがタップされた時に上までスクロールする。あるいはそれを共通化する話。
extension Binding {
func willSet(_ handler: @escaping (Value) -> ()) -> Binding<Value> {
.init(
get: { wrappedValue },
set: { newValue in
handler(newValue)
wrappedValue = newValue
}
)
}
}
enum Tab: String, Identifiable, CaseIterable {
case first
case second
var id: String { rawValue }
var title: String {
switch self {
case .first: return "First"
case .second: return "Second"
}
}
@ViewBuilder
func tabItem() -> some View {
switch self {
case .first: Label(title, systemImage: "1.circle")
case .second: Label(title, systemImage: "2.circle")
}
}
}
/// イベントのトリガー
struct Trigger {
private(set) var key: Bool = false
mutating func fire() {
key.toggle()
}
}
extension View {
func onTrigger(of trigger: Trigger?, perform: @escaping () -> Void) -> some View {
onChange(of: trigger?.key) { _ in
perform()
}
}
}
/// ルートの View
struct ContentView: View {
@State private var selectedTab: Tab = .first
@State private var tabTappedTwices: [SelectionValue: Trigger] = .init(
uniqueKeysWithValues: SelectionValue.allCases.map { ($0, .init()) }
)
var body: some View {
TabView(selection: $selectedTab.willSet {
if selectedTab == $0 {
tabTappedTwice[selectedTab]?.fire()
}
}) {
ForEach(Tab.allCases) { tab in
SampleView(
title: tab.title,
tabTappedTwice: tabTappedTwices[tab]!
)
.tabItem(tab.tabItem)
.tag(tab)
}
}
}
}
/// タブに表示する View
struct SampleView: View {
var title: String
var tabTappedTwice: Trigger
var body: some View {
NavigationView {
ScrollViewReader { proxy in
List {
ForEach(items) { item in
Text(item.title)
.id(items.first?.id == item.id ? "top" : nil)
}
}
.listStyle(.plain)
.onTrigger(of: tabTappedTwice) { _ in
withAnimation {
proxy.scrollTo("top", anchor: .top)
}
}
}
.navigationTitle(title)
.navigationBarTitleDisplayMode(.inline)
}
}
}
/// 要素
struct Item: Identifiable {
var id: Int
var title: String { "Item \(id)" }
init(_ number: Int) {
id = number
}
}
/// ダミーデータ
private let items: [Item] = (1..<100).map(Item.init)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment