2

I have a scrollable widget that I want to convert to image, but when I want to convert the image only shows part of the widget.

In the code example that I upload, when pressing the floating button, it saves the image in the gallery. As you can see, it only saves a part of the widget. Any suggestions on how to save the entire widget? It doesn't matter if it scales.

import 'dart:io';

import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';

import 'dart:ui' as ui;

import 'package:image_save/image_save.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter prueba',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: PruebaApp(),
    );
  }
}

class PruebaApp extends StatelessWidget {
  GlobalKey _globalKey = new GlobalKey();
  // Creamos la lista de nombres
  final List<String> nombres = [
    "Alberto",
    "Ricardo",
    "Francisco",
    "Gustavo",
    "Oscar",
    "Alejandro",
    "Nayla"
  ];

  PruebaApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter prueba'),
      ),
      //Utilizando el Scrollview.builder
      body: buildListView(_globalKey),
      floatingActionButton: botonTips(),
    );
  }

  RepaintBoundary buildListView(GlobalKey key) {
    return RepaintBoundary(
      key: key,
      child: ListView.builder(
        // tamaño de la lista
        itemCount: nombres.length,
        // Constructor de widget para cada elemento de la lista
        itemBuilder: (BuildContext context, int indice) {
          return Card(
            //le damos un color de la lista de primarios
            color: Colors.primaries[indice],
            //agregamos un contenedor de 100 de alto
            child: Container(
                height: 100,
                //Centramos con el Widget <a href="https://zimbronapps.com/flutter/center/">Center</a>
                child: Center(
                  //Agregamos el nombre con un Widget Text
                    child: Text(
                      nombres[indice],
                      //le damos estilo a cada texto
                      style: TextStyle(fontSize: 20, color: Colors.white),
                    ))),
          );
        },
      ),
    );
  }
  FloatingActionButton botonTips() {
    return FloatingActionButton(
      onPressed: () {
        capturePng();
      },
      child: Icon(Icons.lightbulb_outline),
      backgroundColor: Colors.redAccent,
    );
  }
  Future<void> capturePng() async {

    //var repaint = RepaintBoundary.wrap(buildListView(context), 0);
    //var boundary = RenderRepaintBoundary(child:repaint.createRenderObject(context));


    RenderRepaintBoundary boundary =  _globalKey.currentContext.findRenderObject();
    ui.Image image = await boundary.toImage();
    ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    Uint8List pngBytes = byteData.buffer.asUint8List();
    print(pngBytes);
    File.fromRawPath(pngBytes);

    //Uint8List pngBytes=  await createImageFromWidget(SizedBox(height: MediaQuery.of(context).size.height,child: table,));
    final Directory directory = await getApplicationDocumentsDirectory();
    final File file = File('${directory.path}/file.png');
    await file.writeAsBytes(pngBytes);
    Directory dir = Platform.isAndroid
        ? await getExternalStorageDirectory()
        : await getApplicationDocumentsDirectory();
    if (!await file.exists()) {
      await file.create(recursive: true);
      file.writeAsStringSync("test for share documents file");
    }
    bool success = await ImageSave.saveImage(pngBytes, "gif", albumName: "demo");
    //ShareExtend.share(file.path, "file");
  }
}
Junsu Cho
  • 826
  • 7
  • 16

2 Answers2

2

There is a simple way You need wrap SingleChildScrollView Widget to RepaintBoundary. just wrap your Scrollable widget (or his father) with SingleChildScrollView

SingleChildScrollView(
  child: RepaintBoundary(
     key: _globalKey
     child: Column() 
   )
)
WU_C
  • 139
  • 2
  • 7
  • 1
    Thanks! your logic was good but there was a slight problem i faced I got this error ``` 'package:flutter/src/rendering/proxy_box.dart': Failed assertion: line 3089 pos 12: '!debugNeedsPaint': is not true. ``` so if you are following the same issue go : https://stackoverflow.com/questions/57645037/unable-to-take-screenshot-in-flutter – Manish May 27 '21 at 07:38
1

It is not possible now. In the case of Flutter, only the currently displayed screen is drawn, so the invisible part is not drawn. If you want scroll capture, you will have to create a file by converting it to Bitmap using Canvas using CustomPainter Class.

url link : https://www.raywenderlich.com/7560981-drawing-custom-shapes-with-custompainter-in-flutter

url link : How to save a Flutter canvas as a bitmap image?

Junsu Cho
  • 826
  • 7
  • 16