Render Flutter Widgets

In some cases, you may not want to rewrite UI code in the native frameworks for your widgets. This works by generating a png file of the Flutter widget and save it to a shared container between your Flutter app and the home screen widget.

Screenshot 2023-06-07 at 12 57 28 PM

Due to a limitation in dart:ui this method does not work when the App is fully in the background. In those cases you should try to build the UI natively.

For example, say you have a chart in your Flutter app configured with CustomPaint:

class LineChart extends StatelessWidget {  const LineChart({  super.key,  });   @override  Widget build(BuildContext context) {  return CustomPaint(  painter: LineChartPainter(),  child: const SizedBox(  height: 200,  width: 200,  ),  );  } } 
Screenshot 2023-06-07 at 12 33 44 PM

Flutter

To render a Flutter widget to an image, use the renderFlutterWidget method:

var path = await HomeWidget.renderFlutterWidget(  const LineChart(),  key: 'lineChart',  logicalSize: const Size(400, 400), ); 
  • LineChart() is the widget that will be rendered as an image.
  • key is the key in the key/value storage on the device that stores the path of the file for easy retrieval on the native side

iOS

To retrieve the image and display it in a widget, you can use the following SwiftUI code:

  1. In your TimelineEntry struct add a property to retrieve the path:

    struct MyEntry: TimelineEntry {   let lineChartPath: String } 
  2. Get the path from the UserDefaults in getSnapshot:

    func getSnapshot(  ...  let lineChartPath = userDefaults?.string(forKey: "lineChart") ?? "No screenshot available" 
  3. Create a View to display the chart and resize the image based on the displaySize of the widget:

    struct WidgetEntryView : View {   var ChartImage: some View {  if let uiImage = UIImage(contentsOfFile: entry.lineChartPath) {  let image = Image(uiImage: uiImage)  .resizable()  .frame(width: entry.displaySize.height*0.5, height: entry.displaySize.height*0.5, alignment: .center)  return AnyView(image)  }  print("The image file could not be loaded")  return AnyView(EmptyView())  }  } 
  4. Display the chart in the body of the widget's View:

    VStack {  Text(entry.title)  Text(entry.description)  ChartImage  } 

Android

On Android use the following code in your Glance Widget to display the Screenshot of the Flutter Widget

// Access data val data = currentState.preferences  // Get Path val imagePath = data.getString("lineChart", null)  // Add Image to Compose Tree imagePath?.let {  val bitmap = BitmapFactory.decodeFile(it)  Image(androidx.glance.ImageProvider(bitmap), null) }