首页 > 解决方案 > ZoomableScrollView 不再适用于 SwiftUI

问题描述

使用 Swift 5.5、Xcode 13.0、iOS 15.0.1、

由于 Apple 在 SwiftUI 的 ScrollViews 上做得不好(还没有?),我不得不实现自己的可缩放 ScrollView。请参阅下面的代码。

我让它在 iOS13 和 iOS14 上成功运行 - 但现在更新到iOS 15.0.1我不得不意识到它不再有效!

错误信息如下:

objc[10882]: Cannot form weak reference to instance (0x1078d5540) of class _TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_5ImageVS_18_AspectRatioLayout__. It is possible that this object was over-released, or is in the process of deallocation.
dyld4 config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib
(lldb) 

我在SwiftUIPager中拥有所有内容,滑动时问题出现在最后一页。但是,我认为这不是寻呼机的错误,因为我可以用普通的 ImageView 替换 ZoomableScrollView 并且一切正常。因此,我认为 Apple 在他们的 UIViewRepresentable 中搞砸了一些东西。但也许你可以告诉我更多?

这是我的 ZoomableScrollView 的完整代码:

import SwiftUI

struct ZoomableScrollView<Content: View>: UIViewRepresentable {
    
    @Binding var didZoom: Bool
    
    private var content: Content
    
    init(didZoom: Binding<Bool>, @ViewBuilder content: () -> Content) {
        _didZoom = didZoom
        self.content = content()        
    }
    
    func makeUIView(context: Context) -> UIScrollView {
        
        // set up the UIScrollView
        let scrollView = UIScrollView()
        scrollView.delegate = context.coordinator  // for viewForZooming(in:)
        scrollView.maximumZoomScale = 20
        scrollView.minimumZoomScale = 1
        scrollView.bouncesZoom = true
        
        // create a UIHostingController to hold our SwiftUI content
        let hostedView = context.coordinator.hostingController.view!
        hostedView.translatesAutoresizingMaskIntoConstraints = true
        hostedView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        hostedView.frame = scrollView.bounds
        hostedView.backgroundColor = .black
        scrollView.addSubview(hostedView)
        
        return scrollView
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(hostingController: UIHostingController(rootView: self.content), didZoom: $didZoom)
    }
    
    func updateUIView(_ uiView: UIScrollView, context: Context) {
        // update the hosting controller's SwiftUI content
        context.coordinator.hostingController.rootView = self.content
        assert(context.coordinator.hostingController.view.superview == uiView)
    }
    
    // MARK: - Coordinator
    
    class Coordinator: NSObject, UIScrollViewDelegate {
        
        var hostingController: UIHostingController<Content>
        @Binding var didZoom: Bool
        
        init(hostingController: UIHostingController<Content>, didZoom: Binding<Bool>) {
            self.hostingController = hostingController
            _didZoom = didZoom
        }
        
        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            return hostingController.view
        }
        
        func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
            didZoom = !(scrollView.zoomScale == scrollView.minimumZoomScale)
        }
    }
}

标签: swiftuiuiscrollviewscrollviewuiviewrepresentableswiftuipager

解决方案


我终于找到了解决方法。

在类中添加以下代码ZoomableScrollView-UIViewRepresentable

    static func dismantleUIView(_ uiView: UIScrollView, coordinator: Coordinator) {
        uiView.delegate = nil
        coordinator.hostingController.view = nil
    }

推荐阅读