我正在尝试在 SwiftUI 列表中显示丰富的链接,无论我尝试什么,我似乎都无法更改屏幕上链接 View (UIViewRepresentable) 的大小。
特定链接是否有最小尺寸?我怎样才能得到它。添加 .aspectRatio 和 clipped() 将尊重大小,但链接被严重剪裁。不知道为什么链接不会调整 aspectRatio 以适合 View 。
以下部分代码来自以下教程:
https://www.appcoda.com/linkpresentation-framework/
我正在为 LinkView 使用以下 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()
}
}
}
设置 View 的框架或 contentMode(.fit) 或填充或我尝试过的任何其他内容都不会改变 LinkViewRepresentable 框架的大小。我已经在可表示的更新中尝试了 sizeToFit,但没有运气。是否可以在这里控制可表示 View 的大小?以下是附加文件:
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")
}
}
这就是我得到的:最佳答案
对我有用的解决方案是将链接 View 子类化以覆盖内在内容大小。感谢 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) {
}
}
关于ios - 无法在 SwiftUI 列表中更改 LPLinkView 的帧大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70212090/