xcode 无法更改SwiftUI列表中LPLinkView的帧大小

hgtggwj0  于 2023-03-13  发布在  Swift
关注(0)|答案(2)|浏览(220)

我尝试在SwiftUI列表中显示丰富的链接,无论我尝试什么,我似乎都无法更改屏幕上链接视图(UIViewRepresentable)的大小。
某个链接是否有最小大小限制?如何获得该限制?添加.aspectRatio和clipped()会考虑大小,但链接被严重剪切。不确定为什么链接无法调整aspectRatio以适应视图。
以下部分代码源自以下教程:https://www.appcoda.com/linkpresentation-framework/
我正在为链接视图使用以下UIViewRepresentable:

import SwiftUI
import LinkPresentation

struct LinkViewRepresentable: UIViewRepresentable {
 
    typealias UIViewType = LPLinkView
    
    var metadata: LPLinkMetadata?
 
    func makeUIView(context: Context) -> LPLinkView {
        guard let metadata = metadata else { return LPLinkView() }
        let linkView = LPLinkView(metadata: metadata)
        return linkView
    }
 
    func updateUIView(_ uiView: LPLinkView, context: Context) {

    }
}

我对List的看法是:

import SwiftUI
import LinkPresentation

struct ContentView: View {
    
    @ObservedObject var linksViewModel = LinksViewModel()
    
    var links: [(String, String)] = [("https://www.apple.com", "1"), ("https://www.stackoverflow.com", "2")]
    
    var body: some View {
        ScrollView(.vertical) {
            LazyVStack {
                ForEach(links, id: \.self.1) { link in
                    VStack {
                        Text(link.0)
                            .onAppear {
                                linksViewModel.getLinkMetadata(link: link)
                            }
                        if let richLink = linksViewModel.links.first(where: { $0.id == link.1 }) {
                            if let metadata = richLink.metadata {
                                if metadata.url != nil {
                                    LinkViewRepresentable(metadata: metadata)
                                        .frame(width: 200)  // setting frame dimensions here has no effect
                                }
                            }
                        }
                    }
                }
            }
            .padding()
        }
    }
}

设置视图的框架或contentMode(.fit)或padding或我尝试过的任何其他操作都不会改变LinkViewRepresentable的框架大小。我在更新时尝试了representable中的sizeToFit,但没有成功。是否可以在此处控制可表示视图的大小?
以下是其他文件:

import Foundation
import LinkPresentation

class LinksViewModel: ObservableObject {
    
    @Published var links = [Link]()
    
    init() {
        loadLinks()
    }
    
    func createLink(with metadata: LPLinkMetadata, id: String) {
        let link = Link()
        link.id = id
        link.metadata = metadata
        links.append(link)
        saveLinks()
    }
    
    
    fileprivate func saveLinks() {
        do {
            let data = try NSKeyedArchiver.archivedData(withRootObject: links, requiringSecureCoding: true)
            guard let docDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
            try data.write(to: docDirURL.appendingPathComponent("links"))
            print(docDirURL.appendingPathComponent("links"))
        } catch {
            print(error.localizedDescription)
        }
    }
    
    
    fileprivate func loadLinks() {
        guard let docDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let linksURL = docDirURL.appendingPathComponent("links")
        
        if FileManager.default.fileExists(atPath: linksURL.path) {
            do {
                let data = try Data(contentsOf: linksURL)
                guard let unarchived = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [Link] else { return }
                links = unarchived
            } catch {
                print(error.localizedDescription)
            }
        }
    }
    
    func fetchMetadata(for link: String, completion: @escaping (Result<LPLinkMetadata, Error>) -> Void) {

        guard let uRL = URL(string: link) else { return }
        let metadataProvider = LPMetadataProvider()
        metadataProvider.startFetchingMetadata(for: uRL) { (metadata, error) in
            if let error = error {
                print(error)
                completion(.failure(error))
                return
            }
            if let metadata = metadata {
                completion(.success(metadata))
            }
        }
    }
    
    func getLinkMetadata(link: (String, String)) {
        for storedLink in self.links {
            if storedLink.id != link.1 {
                return
            }
        }
        do {
            let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
            let matches = detector.matches(in: link.0, options: [], range: NSRange(location: 0, length: link.0.utf16.count))
            if let match = matches.first {
                guard let range = Range(match.range, in: link.0) else { return }
                let uRLString = link.0[range]
                
                self.fetchMetadata(for: String(uRLString)) { result in
                    self.handleLinkFetchResult(result, link: link)
                }
            }
        } catch {
            print(error)
        }
    }
    
    private func handleLinkFetchResult(_ result: Result<LPLinkMetadata, Error>, link: (String, String)) {
        DispatchQueue.main.async {
            switch result {
                case .success(let metadata):
                self.createLink(with: metadata, id: link.1)
                case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }

}

和链接类:

import Foundation
import LinkPresentation

class Link: NSObject, NSSecureCoding, Identifiable {
    
    var id: String?
    var metadata: LPLinkMetadata?
    
    override init() {
        super.init()
    }
    
    // MARK: - NSSecureCoding Requirements
    
    static var supportsSecureCoding = true

    func encode(with coder: NSCoder) {
        guard let id = id, let metadata = metadata else { return }
        coder.encode(id, forKey: "id")
        coder.encode(metadata as NSObject, forKey: "metadata")
    }
 
    required init?(coder: NSCoder) {
        id = coder.decodeObject(forKey: "id") as? String
        metadata = coder.decodeObject(of: LPLinkMetadata.self, forKey: "metadata")
    }
}

这是我得到的:

9avjhtql

9avjhtql1#

对我来说有效的解决方案是子类化linkView覆盖内在的内容大小,感谢user1046037的评论,使用super.intrinsicContentSize.height将使它能够动态工作。

import SwiftUI
import LinkPresentation

class CustomLinkView: LPLinkView {
    override var intrinsicContentSize: CGSize { CGSize(width: 0, height: super.intrinsicContentSize.height) }
}

struct LinkViewRepresentable: UIViewRepresentable {
 
    typealias UIViewType = CustomLinkView
    
    var metadata: LPLinkMetadata?
 
    func makeUIView(context: Context) -> CustomLinkView {
        guard let metadata = metadata else { return CustomLinkView() }
        let linkView = CustomLinkView(metadata: metadata)
        return linkView
    }
 
    func updateUIView(_ uiView: CustomLinkView, context: Context) {
    }
}

bxgwgixi

bxgwgixi2#

这是我在SwiftUI中的LinkPresentation代码示例

import SwiftUI
import LinkPresentation

自定义类,用于调整内部内容的大小

class CustomLinkView: LPLinkView {
    override var intrinsicContentSize: CGSize {
        CGSize(width: super.intrinsicContentSize.width,
               height: super.intrinsicContentSize.height)
    }
}

ViewModel类(不是SwiftUI的最佳方法)

class LPMeatDataProvider_VM: ObservableObject {

    private let stringURLs: [String] = [
        "https://medium.com", "https://apple.com",
        "https://yahoo.com", "https://stackoverflow.com"
    ]

    @Published var URLs: [URL] = []

    init() { getURLs() }

    func getURLs() {
        stringURLs.forEach { string in
            guard let url = URL(string: string) else { return }
            URLs.append(url)
       }
    }
}

可表示的视图和UIView

struct URLPreviewContainer: UIViewRepresentable {

    @Binding var togglePreview: Bool

    var previewURL: URL

    func makeUIView(context: Context) -> CustomLinkView {
        let view = CustomLinkView(url: previewURL)
        let provider = LPMetadataProvider()
        provider.startFetchingMetadata(for: previewURL) { metadata, error in
            if error == nil, let metadata = metadata {
                DispatchQueue.main.async {
                    view.metadata = metadata
                    togglePreview.toggle()
                }
            }
        }
        return view
    }

    func updateUIView(_ uiView: CustomLinkView, context: Context) {}
}

struct LPMeatDataProvider_: View {

    @State var togglePreview = false
    @StateObject var vm = LPMeatDataProvider_VM()

    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(vm.URLs, id: \.self) { _url in
                    URLPreviewContainer(togglePreview: $togglePreview, previewURL: _url)
                        .padding()
                        .padding(.horizontal)
                }
            }
        }
    }
}

相关问题