您好,我正在创建一个链接预览,为了将自定义框架设置为预览,我必须覆盖内在内容大小并放置我自己的大小。我传递了frame.width和frame.height,它们应该在视图中反映 .frame(maxWidth: 300, maxHeight: 400) 。如果预览最初小于 300*400,我希望它保持当前大小,如果它大于它,则应缩小到 300x400。我面临的问题是将frame.width和frame.height传递给override vartrinsicContentSize导致预览缩放到300x400,这应该只是最大帧,而不是默认帧。因此,诸如此 SO 线程之类的较小预览会拉伸到 300x400 的大小。我如何修改它以在保持最大帧的同时不拉伸预览。
我尝试传递下面的代码,但没有成功。我也尝试过 .scaledToFill、.scalledToFit、.aspectRation(... fit/fill) 但没有一个成功
return CGSize(width: super.intrinsicContentSize.width, height: super.intrinsicContentSize.height)
import SwiftUI
struct SwiftUIView: View {
@State var text = "https://stackoverflow.com/questions/77101513/resize-swift-ui-real-link-to-fit-frame/77102190?noredirect=1#comment135923413_77102190"
var body: some View {
if let url = checkForFirstUrl(text: text){
LinkPreviewView(url: url)
.frame(maxWidth: 300, maxHeight: 400)
.aspectRatio(contentMode: .fit)
}
}
}
struct LinkPreviewView: UIViewRepresentable {
let url: URL
func makeUIView(context: Context) -> UIView {
let linkView = CustomLinkView()
return linkView
}
func updateUIView(_ uiView: UIView, context: Context) {
let provider = LPMetadataProvider()
provider.startFetchingMetadata(for: url) { metaData, error in
guard let data = metaData, error == nil else { return }
DispatchQueue.main.async {
if let linkPreview = uiView as? CustomLinkView {
linkPreview.metadata = data
}
}
}
}
}
class CustomLinkView: LPLinkView {
init() {
super.init(frame: .zero)
}
override var intrinsicContentSize: CGSize {
return CGSize(width: frame.width, height: frame.height)
}
}
func checkForFirstUrl(text: String) -> URL? {
let types: NSTextCheckingResult.CheckingType = .link
do {
let detector = try NSDataDetector(types: types.rawValue)
let matches = detector.matches(in: text, options: .reportCompletion, range: NSMakeRange(0, text.count))
if let firstMatch = matches.first {
return firstMatch.url
}
} catch {
print("")
}
return nil
}
我通过使用 linkView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize) 动态选择大小找到了解决方案这里是代码:
import SwiftUI
struct SwiftUIView: View {
@State var text = "https://wp.titan.email/mail/"
@State var size: CGFloat = .zero
@State var size2: CGFloat = .zero
var body: some View {
VStack {
if let url = checkForFirstUrl(text: text){
LinkPreviewView(url: url, width: $size, height: $size2, message: true)
.frame(width: size, height: size2, alignment: .leading)
.aspectRatio(contentMode: .fill)
.cornerRadius(15)
.padding(.bottom, 200)
}
}
}
}
import LinkPresentation
import UIKit
import SwiftUI
struct LinkPreviewView: UIViewRepresentable {
let url: URL
@Binding var width: CGFloat
@Binding var height: CGFloat
func makeUIView(context: Context) -> UIView {
let linkView = CustomLinkView()
let provider = LPMetadataProvider()
provider.startFetchingMetadata(for: url) { metaData, error in
guard let data = metaData, error == nil else { return }
DispatchQueue.main.async {
linkView.metadata = data
let linksize = linkView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
let width = linksize.width
let height = linksize.height
let goal = widthOrHeight(width: true) * 0.8
if width > goal {
self.width = goal
} else {
self.width = width
}
if height > 400 {
self.height = 400
} else {
self.height = height
}
}
}
return linkView
}
func updateUIView(_ uiView: UIView, context: Context) { }
}
class CustomLinkView: LPLinkView {
init() {
super.init(frame: .zero)
}
override var intrinsicContentSize: CGSize {
return CGSize(width: frame.width, height: frame.height)
}
}
func checkForFirstUrl(text: String) -> URL? {
let types: NSTextCheckingResult.CheckingType = .link
do {
let detector = try NSDataDetector(types: types.rawValue)
let matches = detector.matches(in: text, options: .reportCompletion, range: NSMakeRange(0, text.count))
if let firstMatch = matches.first {
return firstMatch.url
}
} catch {
print("")
}
return nil
}