Closed gesabo closed 2 years ago
@gesabo Did you ever figure this out? I'm running into the same issue
@zcjhnsn no I never did. Ended up using another charts lib for the share function, would love to figure it out though!
@gesabo I got it to work but it feels hacky. Had to "disable" the chart animation using the .transaction
modifier on the superview. Then used a DispatchQueue.main.asyncAfter
block to wait to capture the screenshot until the animation finished. It'll be much cleaner once they officially add support to disable chart animation.
Hey @gesabo and @zcjhnsn, on branch https://github.com/willdale/SwiftUICharts/tree/189-screenshot-chart-in-uiimage-linecharts, is a proposed fix for it. Currently, it is only tested on Line Chart.
Feel free to have a go and offer feedback, I'll look to add in the other chart types and to make it work on iOS 14.
Below is the client side code based off of @gesabo.
Add .disableAnimation(chartData: data)
to the view that will be rendered. - Probably add it just after the chart so it is at the top.
Bear in mind that the view to render doesn't have to be the view that is being displayed - you can tweak the view to be rendered as needed.
#if canImport(UIKit)
enum ActiveSheet: String, Identifiable {
case photoLibrary, shareSheet
var id: String {
return self.rawValue
}
}
struct ShareHomeView: View {
var chartImageController = ChartImageController()
@State var showImage = false
@State var image = UIImage()
@State var bag = Set<AnyCancellable>()
@State private var shareCardAsImage: UIImage? = nil
@State var activeSheet: ActiveSheet? = nil
var shareCard: some View {
LineChartDemoView()
.frame(width: UIScreen.main.bounds.width,
height: UIScreen.main.bounds.height)
}
var body: some View {
Button {
let controller = ChartImageHostingController(rootView: shareCard)
controller.finalImage
.sink { completion in
self.chartImageController.controller = nil
} receiveValue: { image in
self.shareCardAsImage = image
self.activeSheet = .shareSheet
}
.store(in: &bag)
controller.start()
chartImageController.controller = controller
} label: {
HStack {
Image(systemName: "square.and.arrow.up")
.font(.system(size: 20))
Text("Share")
.font(.headline)
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 50, maxHeight: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(20)
}
.padding(.horizontal)
.sheet(item: $activeSheet) { [shareCardAsImage] sheet in
switch sheet {
case .photoLibrary:
Text("TODO")
case .shareSheet:
if let unwrappedImage = shareCardAsImage {
ShareSheet(photo: unwrappedImage)
}
}
}
}
}
struct RecoveryShareHomeView_Previews: PreviewProvider {
static var previews: some View {
ShareHomeView().preferredColorScheme(.dark)
ShareHomeView().preferredColorScheme(.light)
}
}
#endif
import LinkPresentation
//This code is from https://gist.github.com/tsuzukihashi/d08fce005a8d892741f4cf965533bd56
struct ShareSheet: UIViewControllerRepresentable {
let photo: UIImage
func makeUIViewController(context: Context) -> UIActivityViewController {
let activityItems: [Any] = [photo]
return UIActivityViewController(
activityItems: activityItems,
applicationActivities: nil
)
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
Using the code below I'm attempting to build a share feature to share the chart (the demo uses the LineChartDemoView from the example app) however when you try and capture the view (tap on the share button), the lines and points are missing on the SwiftUIChart in the
UIImage
. Is there a way around this issue? I thought it might be related to the animation but setting theanimation
tonil
didn't change the behavior.