SwiftUIでUIKitのカスタムスクロールがうまく機能しない

アプリをつくっているのですが、どうしても解決できない問題があります。

CustomVScrollView内で作っているViewをスクロールごとに更新したいのですが、なぜか変更通知がいってないようです。

基本的に見た目をSwiftUIの構文のまま使いたいので、変更通知を下に通す方向の回答を期待します。

以下コード

struct CustomVScrollView<Content: View>: UIViewRepresentable {
@State var metrics: ScrollMetrics
@ObservedObject var appConfig: AppConfig
var content: () -> Content
var onInit: (() -> Void)? = nil

func makeUIView(context: Context) -> UIScrollView { let scrollView = UIScrollView() scrollView.backgroundColor = UIColor.clear scrollView.delegate = context.coordinator scrollView.showsHorizontalScrollIndicator = false scrollView.showsVerticalScrollIndicator = false scrollView.alwaysBounceVertical = true scrollView.alwaysBounceHorizontal = false scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) let anyContent = AnyView(content().environmentObject(appConfig)) context.coordinator.hostingController = UIHostingController(rootView: anyContent) let hostView = context.coordinator.hostingController!.view! scrollView.addSubview(hostView) hostView.translatesAutoresizingMaskIntoConstraints = false hostView.backgroundColor = UIColor.clear // コンテンツビューのサイズを動的に設定 NSLayoutConstraint.activate([ hostView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor), hostView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor), hostView.widthAnchor.constraint(equalTo: scrollView.contentLayoutGuide.widthAnchor), hostView.heightAnchor.constraint(equalTo: scrollView.contentLayoutGuide.heightAnchor) ]) onInit?() return scrollView } func updateUIView(_ uiView: UIScrollView, context: Context) { uiView.contentOffset.x = metrics.offsetAnother } func makeCoordinator() -> Coordinator { Coordinator(self, metrics: metrics) } func onInit(perform action: @escaping () -> Void) -> CustomVScrollView { var newView = self newView.onInit = action return newView } class Coordinator: NSObject, UIScrollViewDelegate { var metrics: ScrollMetrics var parent: CustomVScrollView var hostingController: UIHostingController<AnyView>? var currentSize: CGSize = .zero var previousScaleX: CGFloat = 1.0 var initialDistanceX: CGFloat? var CurrentDistance: CGFloat = 0 var Touch0: CGPoint = .zero var Touch1: CGPoint = .zero private var cancellables: Set<AnyCancellable> = [] init(_ parent: CustomVScrollView, metrics: ScrollMetrics) { self.metrics = metrics self.parent = parent super.init() } func updateContent() { } func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { guard let scrollView = hostingController?.view.superview as? UIScrollView else { return } switch scrollView.traitCollection.userInterfaceStyle { case .light: metrics.backgroundColor = .black case .dark: metrics.backgroundColor = .white default: metrics.backgroundColor = .gray } } func scrollViewDidScroll(_ scrollView: UIScrollView) { scrollView.contentOffset.x = metrics.offsetAnother metrics.offset = scrollView.contentOffset.y - metrics.ppLength metrics.offsetUnit = Int(metrics.offset/metrics.unitLength) metrics.offsetLength = metrics.offset - CGFloat(metrics.offsetUnit)*metrics.unitLength if metrics.offset > metrics.marginLength { if !metrics.doLoop && metrics.maxContentUnit >= metrics.viewLastUnit { if metrics.maxContentUnit >= metrics.viewLastUnit + metrics.marginUnit { scrollView.contentOffset.y -= metrics.marginLength metrics.viewStartUnit += metrics.marginUnit metrics.viewLastUnit += metrics.marginUnit } else { scrollView.contentOffset.y -= CGFloat(metrics.maxContentUnit - metrics.viewLastUnit) * metrics.unitLength metrics.viewStartUnit += metrics.maxContentUnit - metrics.viewLastUnit metrics.viewLastUnit = metrics.maxContentUnit } } metrics.dataID = UUID() } else if metrics.offset < 0 { if !metrics.doLoop && metrics.viewStartUnit > 0 { if 0 <= metrics.viewStartUnit - metrics.marginUnit { scrollView.contentOffset.y += metrics.marginLength metrics.viewStartUnit -= metrics.marginUnit metrics.viewLastUnit -= metrics.marginUnit } else { scrollView.contentOffset.y += CGFloat(metrics.viewStartUnit) * metrics.unitLength metrics.viewLastUnit -= metrics.viewStartUnit metrics.viewStartUnit = 0 } } metrics.dataID = UUID() } } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { if !decelerate { if metrics.didScroll { } else { metrics.didScroll = true } } else { metrics.didScroll = false } } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { metrics.didScroll = true } }

}

struct MembearView: View {
@ObservedObject var appConfig: AppConfig

@State private var viewID = UUID() @State private var showingEditScreen = false // 編集画面の表示状態 @State private var selectedMember: MemberStr? var body: some View { VStack { GeometryReader { geoView in if !appConfig.sortData.member.isEmpty { CustomVScrollView (metrics: appConfig.csv.member, appConfig: appConfig){ VStack(alignment: .leading, spacing: 0) { ForEach(appConfig.csv.member.viewStartUnit..<appConfig.csv.member.viewLastUnit, id: \.self) { i in HStack { MemberRowView(member: appConfig.sortData.member[i], showingEditScreen: $showingEditScreen, selectedMember: $selectedMember) .environmentObject(appConfig) Spacer() } } } .onChange(of:appConfig.csv.member.dataID) { print("appConfig.csv.member.viewStartUnit: \(appConfig.csv.member.viewStartUnit)") print("appConfig.csv.member.viewLastUnit: \(appConfig.csv.member.viewLastUnit)")

//更新されていない
}
.id(appConfig.csv.member.dataID)
}
.onInit {
appConfig.csv.member.setInit(unit: appConfig.size.member.main.m.y , length: geoView.size.height ,margin: 5, max: appConfig.sortData.member.count)
appConfig.csv.member.viewLastUnit = appConfig.csv.member.maxViewUnit + appConfig.csv.member.marginUnit + appConfig.csv.member.ppUnit*2
}
.onChange(of:appConfig.csv.member.dataID) {
print("appConfig.csv.member.viewStartUnit: (appConfig.csv.member.viewStartUnit)")
print("appConfig.csv.member.viewLastUnit: (appConfig.csv.member.viewLastUnit)")
//更新されている
}
}
}
}
}
}

コメントを投稿

0 コメント