The goal is to utilize SwiftUI ShareLink
to render, and share a specific portion of a SwiftUI View to Messages, Instagram, and other social media applications. My question is, what is the appropriate method to do so and retain all styling of that portion of the view?
struct SelectedEntryShareView: View {
let title: String
let entry: String
let entryDate: Date
@State private var renderedImage = Image("")
var body: some View {
VStack {
Spacer()
content
Spacer()
}
.frame(maxWidth: .infinity)
.background(Color("Base"))
.safeAreaInset(edge: .bottom) {
shareButtons
}
.task {
if !title.isEmpty && !entry.isEmpty {
renderedImage = renderContent(content: content)
}
}
}
}
extension SelectedEntryShareView {
var content: some View {
ScrollView {
VStack {
Text(entryDate.formatted(date: .abbreviated, time: .shortened))
.font(.callout)
.fontWeight(.semibold)
.foregroundStyle(.accent)
.padding(.top)
Text(title)
.font(.title)
.bold()
.padding(.bottom, 5)
Text(entry)
.frame(alignment: .leading)
SelectedEntryShareViewFooter()
}
.padding(.horizontal)
}
.frame(minWidth: 300, maxWidth: 400, minHeight: 200, maxHeight: 500)
.background {
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(Color("Highlight"))
}
}
var shareButtons: some View {
HStack {
ShareLink(item: renderedImage, preview: SharePreview(title, image: renderedImage)) {
Image(systemName: "message.circle")
.padding()
.foregroundStyle(.white)
.background {
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(.secondary)
}
}
Button {
} label: {
Image(systemName: "ellipsis.circle")
.padding()
.foregroundStyle(.white)
.background {
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(.secondary)
}
}
}
.font(.title)
}
@MainActor func renderContent(content: some View) -> Image {
let renderer = ImageRenderer(content: content)
guard let image = renderer.uiImage else { fatalError() }
return Image(uiImage: image)
}
}
As you can see, I have a function which renders the content into a UIImage, then converts it to an Image. I wasn't sure what to do to pass the image to the ShareLink so I opted for a @State
variable which is then changed. The current method leaves me with a blank rectangle shown below. I have also included a picture of what I want my desired output to be similar to.
Using this Hacking with Swift article. I was able to determine that I needed to add @MainActor
to the view I was attempting to use ImageRenderer
on. This allowed me to then call my asynchronous ImageRenderer
function directly inside of the ShareLink
.