skip to Main Content

Hello Ive created a real link in swift that displays a site with a preview. I want the preview to have a frame with maxWidth of 300 and maxHeight of 200. When I do so the preview is distorted. I tried adding a scalled to fit and fill along with .aspect ratio modifiers, this didn’t work. How can I resize the preview so it fits the frame without cutting out part of the preview?

This is how the preview is supposed to look image1

and this is what happens when I want to make it smaller: image2

import SwiftUI

struct SwiftUIView: View {
    @State var text = "https://www.youtube.com/watch?v=Phaq5p6SAmM"
    
    var body: some View {
        if let url = checkForFirstUrl(text: text){
            LinkPreviewView(url: url)
                .aspectRatio(contentMode: .fill)
                .frame(maxWidth: 300, maxHeight: 200, alignment: .leading)
                .cornerRadius(15)
        }
    }
}



import LinkPresentation
import UIKit
import SwiftUI

struct LinkPreviewView: UIViewRepresentable {
    let url: URL

    func makeUIView(context: Context) -> UIView {
        return LPLinkView()
    }

    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? LPLinkView {
                    linkPreview.metadata = data
                }
            }
        }
    }
}

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
}

2

Answers


  1. Chosen as BEST ANSWER

    Based on Elevo's answer, Here is the complete Solution:

    struct SwiftUIView: View {
        @State var text = "https://www.youtube.com/watch?v=Phaq5p6SAmM"
        
        var body: some View {
            if let url = checkForFirstUrl(text: text){
                LinkPreviewView(url: url).cornerRadius(15)
            }
        }
    }
    
    import LinkPresentation
    import UIKit
    import SwiftUI
    
    struct LinkPreviewView: UIViewRepresentable {
        let url: URL
    
        func makeUIView(context: Context) -> UIView {
            let linkView = CustomLinkView()
            linkView.translatesAutoresizingMaskIntoConstraints = false
            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? LPLinkView {
                        linkPreview.metadata = data
                    }
                }
            }
        }
    }
    
    class CustomLinkView: LPLinkView {
        
        init() {
            super.init(frame: .zero)
        }
        
        override var intrinsicContentSize: CGSize {
            CGSize(width: 300, height: 150)
        }
    }
    
    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
    }
    

    Thanks @Elevo


  2. After a lot of tests, I find that frame.size = (300, 200) and intrinsicSize = (350, 285), so the preview should get clipped.

    I think the problem is the frame setted by LinkPreviewView is not matched by LPLinkView’s intrinsicSize

    You can have a try

    class CustomLinkView: LPLinkView {
        init() {
            super.init(frame: .zero)
        }
        
        override var intrinsicContentSize: CGSize {
            CGSize(width: frame.width, height: frame.height)
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search