skip to Main Content

I will prefix this by saying I have quite limited Swift and SwiftUI experience, so there might be some obvious things that I have missed.

My problem is split into multiple areas of concern

  1. I want to render a text link using markdown within a Text view in SwiftUI
  2. I want the label for this link to contain an image alongside some text so that the text and image are both clickable
  3. I need this to be done inside a Text view which I can then append to the end of another Text view.

Some context

I have several paragraphs of text, each one coming from a specific source which I want to provide a link to. The link should be inline with the text and at the end of each paragraph, and should be in the format "Source <icon>". I believe SwiftUI’s support for markdown is the easiest way to achieve this, as it allows a simple Text view to contain a hyperlink by doing: Text(.init("[Source](https://example.com)")). This has got me quite far, but I am missing the crucial step of including the icon as part of the link label. As of now, I have been forced to add the icon after the actual link text as per the example below.

So my question boils down to: Is there a way to render an image inside a markdown string in SwiftUI?

Simplified example of my code setup

import SwiftUI

struct Paragraph {
  text: String
  url: String
}

struct ParagraphView: View {
  let paragraph: Paragraph

  var body: some View {
    Text(paragraph.text)

    // Less than ideal solution I have currently
    + Text(.init(" [Source]((paragraph.url)) "))

    + Text(Image(systemName: "star")) // Example icon
  }
}

Ideally, I would like to do something like this

struct ParagraphView: View {
  let paragraph: Paragraph

  var body: some View {
    Text(paragraph.text)

    + Text(.init(" [Source (IMAGE)]((paragraph.url))"))
  }
}

I have tried using both AttributedString and NSAttributedString to achieve this

struct ParagraphView: View {
  let paragraph: Paragraph

  var markdown: String {
    let str = NSMutableAttributedString(string: " [Source ")

    let iconAttachment = NSTextAttachment()
    iconAttachment.image = UIImage(systemName: "star")
    let iconText = NSAttributedString(attachment: iconAttachment)

    str.append(iconText)
    str.append(NSAttributedString(string: "]((paragraph.url))"))

    return str.string
  }

  var body: some View {
    Text(paragraph.text)

    // Link works, but image is not rendered
    + Text(.init(markdown))
  }
}

2

Answers


  1. Instead of using markdown to display an image within some text,
    you could try a different simple but versatile approach using two HStack a .onTapGesture with openURL,
    as shown in the example code.

    struct ParagraphView: View {
        @Environment(.openURL) private var openURL
        let paragraph: Paragraph
        
        var body: some View {
            HStack {
                Text(paragraph.text)
                HStack {
                    Text("Source")
                    Image(systemName: "star")
                }.foregroundStyle(.blue)
                    .onTapGesture {
                        if let url = URL(string: paragraph.url) {
                            openURL(url)
                        }
                    }
            }
        }
    }
    
    struct Paragraph {
        var text: String = "paragraph text"
        var url: String = "https://www.apple.com/"
    }
    
    struct ContentView: View {
        var body: some View {
            ParagraphView(paragraph: Paragraph())
        }
    }
    
    Login or Signup to reply.
  2. Currently, it seems that Images still aren’t supported by Swift UI.

    Note: Images aren’t supported.

    Source

    There are probably other libraries out there for this, you’ll have to pick one if you want to add images in markdown.

    This article also discusses the issue and introduces this package which is compatible with GitHub’s Markdown Spec.
    Because of that compatibility, you’ll then be able to use all the normal markdown that you’re used to:

    ![image](https://httpcats.com/200.jpg)
    

    ↓↓

    image

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search