概要
TCAのReducerからスクロールビューのスクロール位置の操作をする方法がわからなかったのですが、NotificationCenterを使ったら出来ました。
他にもっと良い方法はあるかもしれません。
ソースコード
github: https://github.com/k-yamada/TCAScrollFromReducer
NSNotification+.swift
extension NSNotification {
static let scrollUp = Notification.Name.init("scrollUp")
static let scrollDown = Notification.Name.init("scrollDown")
}
AppView.swift
struct AppView: View {
let store: Store<AppState, AppAction>
let items = (1...100)
var body: some View {
WithViewStore(store) { viewStore in
ScrollViewReader { scrollProxy in
ZStack {
ScrollView {
ForEach(items, id: \.self) { Text("\($0)"); Divider() }
}
.onReceive(NotificationCenter.default.publisher(for: NSNotification.scrollUp)) { _ in
scrollProxy.scrollTo(items.first!)
}
.onReceive(NotificationCenter.default.publisher(for: NSNotification.scrollDown)) { _ in
scrollProxy.scrollTo(items.last!)
}
VStack {
Spacer()
HStack {
Button("Up") {
viewStore.send(.upButtonTapped)
}
Spacer()
Button("Down") {
viewStore.send(.downButtonTapped)
}
}
}.padding(EdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20))
}
}
}
}
}
AppCore.swift
import ComposableArchitecture
import SwiftUI
struct AppState: Equatable {
}
enum AppAction: Equatable {
case upButtonTapped
case downButtonTapped
}
struct AppEnvironment {
var mainQueue: AnySchedulerOf<DispatchQueue>
}
let appReducer = Reducer<AppState, AppAction, AppEnvironment> { state, action, environment in
switch action {
case .upButtonTapped:
NotificationCenter.default.post(name: NSNotification.scrollUp, object: nil, userInfo: nil)
return .none
case .downButtonTapped:
NotificationCenter.default.post(name: NSNotification.scrollDown, object: nil, userInfo: nil)
return .none
}
}