Im trying to understand tensorflow and I wanted to create a flutter app with Image Classification for cat or dog.
I used https://teachablemachine.withgoogle.com/ to train my model with 100 epoches and 128 batches. The ouput of my model is 97% accuracy for both the cat and dog. I used a dataset from kaggle with 4000 images for each cat and dog.
My Code:
import 'dart:io';
import 'package:tflite/tflite.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File? _image;
bool _loading = false;
List<dynamic>? _output;
final _picker = ImagePicker();
pickImage() async {
var image = await _picker.getImage(source: ImageSource.camera);
if (image == null) {
return null;
}
setState(() {
_image = File(image.path);
});
classifyImage(_image);
}
pickGalleryImage() async {
var image = await _picker.getImage(source: ImageSource.gallery);
if (image == null) {
return null;
}
setState(() {
_image = File(image.path);
});
classifyImage(_image);
}
#override
void initState() {
super.initState();
_loading = true;
loadModel().then((value) {
// setState(() {});
});
}
#override
void dispose() {
Tflite.close();
super.dispose();
}
classifyImage(File? image) async {
var output = await Tflite.runModelOnImage(
path: image!.path,
numResults: 2,
threshold: 0.5,
imageMean: 127.5,
imageStd: 127.5,
);
setState(() {
_loading = false;
_output = output;
});
}
loadModel() async {
await Tflite.loadModel(
model: 'assets/model_unquant.tflite',
labels: 'assets/labels.txt',
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cat vs Dog Classifier'),
),
body: Center(
child: Column(
children: [
SizedBox(height: 160.0),
_image == null
? Text('No image selected')
: Container(
child: Image.file(_image!),
height: 250.0, // Fixed height for image
),
SizedBox(height: 20.0),
_output != null ? Text('${_output![0]['label']}') : Container(),
SizedBox(height: 50.0),
ElevatedButton(
onPressed: pickImage,
child: Text('Take Picture'),
),
ElevatedButton(
onPressed: pickGalleryImage,
child: Text('Camera Roll'),
),
],
),
),
);
}
}
My question:
If im picking a different image which isn't cat or dog, im still getting a 100% cat or dog feedback most of the time. How to not show these wrong results? What can we actually do?
You have to train Your original model on 3 classes:
cat
dog
other
then convert to tflite model and use it in your flutter project
Related
mic image code
Center(
child: Padding(
padding: const EdgeInsets.only(top: 1),
child: IconButton(
iconSize: 45,
icon: Ink.image(
image: const AssetImage('assets/mic.png'),
),
onPressed: () {
// do something when the button is pressed
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Recorder12Screen()),
);
// RecorderDialogScreen(context);
},
),
),
),
when click this mic image I want display voice recording page as a pop up window.
recording page image... my output
But I wanna like this
I my voice recording function has 2 pages
and this
2nd page is then the click pause button then display playback page
both pages I wanna display as pop up windows
1st page
2nd page
1st page code
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:kathana/screens/voiceRecord/voiceRecord12/recorder/feature_buttons_view.dart';
import 'package:provider/provider.dart';
import '../../../provider/sign_in_provider.dart';
class Recorder12Screen extends StatefulWidget {
#override
State<Recorder12Screen> createState() => _Recorder12ScreenState();
}
class _Recorder12ScreenState extends State<Recorder12Screen> {
String? downloadURL;
List<Reference> references = [];
#override
void initState() {
super.initState();
_onUploadComplete();
}
//snack bar for showing error
showSnackBar(String snackText, Duration d) {
final snackBar = SnackBar(content: Text(snackText), duration: d);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
#override
Widget build(BuildContext context) {
final sp = context.read<SignInProvider>();
return Scaffold(
body: Column(
children: [
Expanded(
flex: 2,
child: FeatureButtonsView(
onUploadComplete: _onUploadComplete,
),
),
Text(
"${sp.uid}",
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
],
),
);
}
Future<void> _onUploadComplete() async {
final sp = context.read<SignInProvider>();
FirebaseStorage firebaseStorage = FirebaseStorage.instance;
ListResult listResult = await firebaseStorage
.ref()
.child("${sp.uid}/records")
.child("voices")
.list();
setState(() {
references = listResult.items;
});
}
}
2nd page code
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_audio_recorder2/flutter_audio_recorder2.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import '../../../../provider/sign_in_provider.dart';
class FeatureButtonsView extends StatefulWidget {
final Function onUploadComplete;
FeatureButtonsView({
Key? key,
required this.onUploadComplete,
}) : super(key: key);
#override
_FeatureButtonsViewState createState() => _FeatureButtonsViewState();
String? userId;
}
class _FeatureButtonsViewState extends State<FeatureButtonsView> {
late bool _isPlaying;
late bool _isUploading;
late bool _isRecorded;
late bool _isRecording;
late AudioPlayer _audioPlayer;
late String _filePath;
late FlutterAudioRecorder2 _audioRecorder;
Future getData() async {
final sp = context.read<SignInProvider>();
sp.getDataFromSharedPreferences();
}
String downloadUrl = '';
Future<void> onsend() async {
//uploading to cloudfirestore
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
final sp = context.read<SignInProvider>();
await firebaseFirestore
.collection("users")
.doc("${sp.uid}")
.collection("reco")
.add({'downloadURL': downloadUrl}).whenComplete(() =>
showSnackBar("Voice uploaded successful", Duration(seconds: 2)));
}
//snackbar for showing error
showSnackBar(String snackText, Duration d) {
final snackBar = SnackBar(content: Text(snackText), duration: d);
}
#override
void initState() {
super.initState();
_isPlaying = false;
_isUploading = false;
_isRecorded = false;
_isRecording = false;
_audioPlayer = AudioPlayer();
final sp = context.read<SignInProvider>();
FirebaseFirestore.instance
.collection("users")
.doc(sp.uid)
.get()
.then((value) {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Center(
child: _isRecorded
? _isUploading
? Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: LinearProgressIndicator()),
Text('Uplaoding to Firebase'),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.replay),
onPressed: _onRecordAgainButtonPressed,
),
IconButton(
icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: _onPlayButtonPressed,
),
IconButton(
icon: Icon(Icons.upload_file, color: Colors.green),
onPressed: _onFileUploadButtonPressed,
),
],
)
: IconButton(
icon: _isRecording
? Icon(Icons.pause)
: Icon(Icons.fiber_manual_record),
onPressed: _onRecordButtonPressed,
),
);
}
Future<void> _onFileUploadButtonPressed() async {
FirebaseStorage firebaseStorage = FirebaseStorage.instance;
setState(() {
_isUploading = true;
});
try {
final sp = context.read<SignInProvider>();
Reference ref = firebaseStorage.ref().child("${sp.uid}/records1").child(
_filePath.substring(_filePath.lastIndexOf('/'), _filePath.length));
TaskSnapshot uploadedFile = await ref.putFile(File(_filePath));
if (uploadedFile.state == TaskState.success) {
downloadUrl = await ref.getDownloadURL();
}
widget.onUploadComplete();
onsend(); //send downloadURL after get it
} catch (error) {
print('Error occured while uplaoding to Firebase ${error.toString()}');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error occured while uplaoding'),
),
);
} finally {
setState(() {
_isUploading = false;
});
}
}
void _onRecordAgainButtonPressed() {
setState(() {
_isRecorded = false;
});
}
Future<void> _onRecordButtonPressed() async {
if (_isRecording) {
_audioRecorder.stop();
_isRecording = false;
_isRecorded = true;
} else {
_isRecorded = false;
_isRecording = true;
await _startRecording();
}
setState(() {});
}
void _onPlayButtonPressed() {
if (!_isPlaying) {
_isPlaying = true;
_audioPlayer.play(_filePath, isLocal: true);
_audioPlayer.onPlayerCompletion.listen((duration) {
setState(() {
_isPlaying = false;
});
});
} else {
_audioPlayer.pause();
_isPlaying = false;
}
setState(() {});
}
Future<void> _startRecording() async {
final bool? hasRecordingPermission =
await FlutterAudioRecorder2.hasPermissions;
if (hasRecordingPermission ?? false) {
Directory directory = await getApplicationDocumentsDirectory();
String filepath = directory.path +
'/' +
DateTime.now().millisecondsSinceEpoch.toString() +
'.aac';
_audioRecorder =
FlutterAudioRecorder2(filepath, audioFormat: AudioFormat.AAC);
await _audioRecorder.initialized;
_audioRecorder.start();
_filePath = filepath;
setState(() {});
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Center(child: Text('Please enable recording permission'))));
}
}
}
Those 2 pages, how convert to like as a popup?
My voice recording functions work perfectly I'm asking to convert those two material pages to like popup windows.
You can use this package for recording the voice :
dependencies:
flutter_sound: ^9.2.13
I am working on a Flutter app to take image from gallery and predict the appropriate output via detection using the model I trained using Machine learning but, I am getting an error for this following code:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:tflite/tflite.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
home: HomePage(),
));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late bool _isLoading;
late File _image;
late List _output;
#override
void initState() {
// TODO: implement initState
super.initState();
_isLoading = true;
loadMLModel().then((value){
setState(() {
_isLoading = false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Brain Tumor Detection"),
),
body: _isLoading ? Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
) : SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_image == null ? Container() : Image.file(File(_image.path)),
SizedBox(height: 16,),
_output == null ? Text(""): Text(
"${_output[0]["label"]}"
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
chooseImage();
},
child: Icon(
Icons.image
),
)
,
);
}
chooseImage() async {
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return null;
setState(() {
_isLoading = true;
_image = image as File;
});
runModelOnImage(image);
}
runModelOnImage(File image) async{
var output = await Tflite.runModelOnImage(
path: image.path,
numResults: 2,
imageMean: 127.5,
imageStd: 127.5,
threshold: 0.5
);
setState(() {
_isLoading = false;
_output = output!;
});
}
loadMLModel() async {
await Tflite.loadModel(
model: "assets/btc.tflite",
labels: "assets/labels.txt"
);
}
}
The error is:
The argument type 'XFile' can't be assigned to the parameter type 'File'.
I have tried all the other alternatives given out there for imagepicker issues faced by other people. Any help to solve this would be great!
Thank you in advance!!
chooseImage() async {
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return null;
setState(() {
_isLoading = true;
_image = File(image.path);
});
runModelOnImage(_image);
}
I was facing the same issue. What I did was:
Created a variable of XFile in my widget XFile? _image;
Look at this function
Future getImageFromGallery() async {
_image = await ImagePicker()
.pickImage(source: ImageSource.gallery, maxHeight: 300, maxWidth: 300);
if (_image!.path.isNotEmpty) {
setState(() {
pickedImage = true;
});
}
}
On the press of a button, called the above function.
Used the follwing function to upload file on Firebase storage
Future uploadLogo(BuildContext? context, XFile? image) async {
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref = storage
.ref()
.child('shops/${_name.text}/Logo${DateTime.now().toString()}');
final path = image!.path; //Getting the path of XFile
File file = File(path);// Turning that into File
UploadTask uploadTask = ref
.putFile(file); //Getting a proper reference to upload on storage
final TaskSnapshot downloadUrl = (await uploadTask); //Uploading to //storage
imageUrlShop = await downloadUrl.ref.getDownloadURL();
}
My answer is almost same as of the earlier ones but there is a little change in the format and how the argument is being passed. This is working for me. Might work for you too...
You are calling runModelOnImage which takes a File as an argument, with an XFile.
chooseImage() async {
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return null;
setState(() {
_isLoading = true;
_image = File(image.path);
});
runModelOnImage(_image);
}
I'm using sdk 2.12.0 and image_picker 0.8.4 version.
I'm going to link my gallery to get an image.
However, when I press the Add Image button on my app, the app turns off immediately.
This is the code for the image_picker I used.
class CreatePage extends StatefulWidget {
const CreatePage({Key? key, required this.user}) : super(key: key);
final User user;
#override
_CreatePageState createState() => _CreatePageState();
}
class _CreatePageState extends State<CreatePage> {
//ImagePicker
final ImagePicker _picker = ImagePicker();
File? _imageFile;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppbar(),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: _getImage,
backgroundColor: Colors.blue,
child: Icon(Icons.add_a_photo),
),
);
}
Future<void> _getImage() async {
//ImagePiker
var image = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(image!.path);
});
}
And this is my full code about this page. (Firebase code is included)
import 'dart:io';
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class CreatePage extends StatefulWidget {
//user info
const CreatePage({Key? key, required this.user}) : super(key: key);
final User user;
#override
_CreatePageState createState() => _CreatePageState();
}
class _CreatePageState extends State<CreatePage> {
//input text
final TextEditingController createText = TextEditingController();
//ImagePicker
final ImagePicker _picker = ImagePicker();
File? _imageFile;
//_createPageState가 제거될 때 호출됨
#override
void dispose() {
// TODO: implement dispose
createText.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppbar(),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: _getImage,
backgroundColor: Colors.blue,
child: Icon(Icons.add_a_photo),
),
);
}
_buildAppbar() {
return AppBar(
actions: [
IconButton(
icon: Icon(Icons.send),
onPressed: () {
_uploadPost(context);
},
),
],
);
}
_buildBody() {
return SingleChildScrollView(
child: Column(
children: [
_imageFile == null ? Text("No Image") : Image.file(_imageFile!),
TextField(
controller: createText,
decoration: InputDecoration(
hintText: "내용을 입력하세요",
),
)
],
),
);
}
//gallery image
Future<void> _getImage() async {
var image = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(image!.path);
});
}
Future _uploadPost(BuildContext context) async {
final firebaseStorageRef = FirebaseStorage.instance
.ref()
.child('post')
.child('${DateTime.now().microsecondsSinceEpoch}.png');
final task = await firebaseStorageRef.putFile(
_imageFile!, SettableMetadata(contentType: "image/png")
);
final uri = await task.ref.getDownloadURL();
//database document
final doc = FirebaseFirestore.instance.collection('post').doc();
//json type
await doc.set({
'id': doc.id,
'photoUrl': uri.toString(), //storage file url
'contents': createText, //user input text
'email': widget.user.email, //user email
'displayName': widget.user.displayName, //user name
'userPhotoUrl': widget.user.photoURL, //user profile image
});
//return page
Navigator.pop(context);
}
}
Pressing the floatingActionButton turns off the app and outputs the following error.
Lost connection to device.
May I know the cause of this?
Thank you in advance.
try adding dependency
image_picker: ^0.8.3+2
import 'package:image_picker/image_picker.dart';
then add this code
String url = "";
ImagePicker image = ImagePicker();
File ? file;
getImage() async {
var img = await image.pickImage(source: ImageSource.gallery);
setState(() {
file = File(img!.path);
});
}
And add:
onTap: () {
getImage();
},
add code:
child: file != null ?
Column(
children: [
Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
color: Colors.black,
margin: EdgeInsets.only(top: 80),
width: double.infinity,
height: 250,
child: Image.file(
file!,
fit: BoxFit.contain,
),
),
),
My guess is that you don't have permission to access the Media on the device, thus aborting the app the moment you try to do so. Check out the permission handler package.
The error is with this line: File selectedImage
I only have dart.io imported, not even dart.html so I'm not sure why I'm getting this error.
here is the longer piece of code
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:random_string/random_string.dart';
import 'package:tennis_event_app/services/crud.dart';
class CreateBlog extends StatefulWidget {
#override
_CreateBlogState createState() => _CreateBlogState();
}
class _CreateBlogState extends State<CreateBlog> {
late String pass, authorName, title, desc;
File selectedImage;
final picker = ImagePicker();
bool _isLoading = false;
CrudMethods crudMethods = new CrudMethods();
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
selectedImage = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
(this is not the entire code but just a larger piece)
What exact error are you getting?
Suggestion
Please do well to put setState((){...}); in the if-statement like this:
if(pickedFile != null){
setState((){
selectedImage = File(pickedFile.path);
});
}else{
print('No image selected');
}
and Hot Reload.
SEE COMPLETE SOLUTION THAT WORKED FOR ME
class _ImageSelectorState extends State<ImageSelector> {
var imageFile;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 200.0,
height: 200.0,
color: Colors.grey.shade300,
child: imageFile != null
? Image.file(imageFile)
: Icon(
Icons.image,
),
),
SizedBox(height: 20.0),
//Button
Center(
child: ElevatedButton(
onPressed: _pickImage,
child: Text('Upload Image'),
),
),
],
),
);
}
_pickImage() async {
try {
final picker = await ImagePicker().getImage(
source: ImageSource.gallery,
);
if (picker != null) {
setState(() {
imageFile = File(picker.path);
});
}
} catch (e) {
print(e);
}
}
}
Result
Solution I Used:
I ended up changing File selectedImage; to File ? selectedImage;
I want to take a screenshot of a screen but I want to hide/blur/paint some Widgets in the resulting screenshot, but not in the app.
Something like this:
The first picture is what I want to see in the app, no changes.
The second picture is what I want to see in the screenshot, a specific widget painted.
My first thought was to calculate absolute coordinates of the specific widget, but in order to do this, I should add a GlobalKey to each of the widgets of the screen, and this is not feasible for my case.
How to do this without adding a GlobalKey to each of the widgets of the screen?
My current approach for taking a screenshot is:
final pixelRatio = MediaQuery.of(context).devicePixelRatio;
final boundary = boundaryKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
final image = await boundary.toImage(pixelRatio: pixelRatio);
This is what I'm using to get coordinates of a Widget that has a GlobalKey:
extension GlobalKeyExtension on GlobalKey {
Rect? get globalPaintBounds {
final renderObject = currentContext?.findRenderObject();
var translation = renderObject?.getTransformTo(null).getTranslation();
if (translation != null) {
return renderObject!.paintBounds
.shift(Offset(translation.x, translation.y));
} else {
return null;
}
}
}
screenshot widget is what you are looking for.
In your pubspec.yaml file add the following line under dependencies
dependencies:
screenshot: ^0.3.0
Then you can use it like so. I just added some buttons and containers to show case it. You can customize it for your needs. Basically what this does is When you put a widget as a child of a Screenshot widget with a controller, you can capture it as an image.
import 'dart:math';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:screenshot/screenshot.dart';
class ScreenCapture extends StatefulWidget {
ScreenCapture({Key key}) : super(key: key);
#override
_ScreenCaptureState createState() => _ScreenCaptureState();
}
class _ScreenCaptureState extends State<ScreenCapture> {
Uint8List _imageFile;
Color captureColor = Colors.red, inAppColor = Colors.green, inAppImageBG;
String capturingText = "Capturing State";
String inAppDisplayText = "In App Display";
String inAppText;
ScreenshotController screenshotController = new ScreenshotController();
#override
void initState() {
super.initState();
inAppImageBG = inAppColor;
inAppText = inAppDisplayText;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [capturedImageContainer(), inAppImage(), capture()],
),
);
}
Widget capturedImageContainer() {
return _imageFile != null
? Container(
color: Colors.black,
height: 100,
width: 300,
child: Image.memory(_imageFile),
)
: Container(color: Colors.black, height: 100, width: 300);
}
Widget inAppImage() {
return Screenshot(
controller: screenshotController,
child: Container(
color: inAppImageBG,
height: 100,
width: 300,
child: Text(inAppText),
alignment: Alignment.center,
),
);
}
Widget capture() {
return GestureDetector(
onTap: () {
doCapture();
},
child: Container(
height: 100,
width: 300,
color: Colors.amber,
child: Text("Capture"),
alignment: Alignment.center,
),
);
}
doCapture() async {
Future.delayed(const Duration(milliseconds: 500), () {
setState(() {
inAppImageBG = captureColor;
inAppText = capturingText + Random().nextInt(10).toString();
Future.delayed(const Duration(milliseconds: 10), () {
screenshotController
.capture(delay: Duration(milliseconds: 1))
.then((Uint8List image) async {
setState(() {
_imageFile = image;
Future.delayed(const Duration(milliseconds: 1500), () {
setState(() {
inAppImageBG = inAppColor;
inAppText = inAppDisplayText;
});
});
});
}).catchError((onError) {
print(onError);
});
});
});
});
}
}
I think you need to declare:
bool _hideWidget = false;
Next you this value with all widgets that you want to hide while taking screenshot:
floatingActionButton: _hideWidget ? const SizedBox.shrink() : FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
In method that you use for taking screenshot, use next:
Future takeScreenShot() async {
final RenderRepaintBoundary boundary = previewContainer.currentContext!.findRenderObject()! as RenderRepaintBoundary;
if (boundary.debugNeedsPaint) {
print("Waiting for boundary to be painted.");
await Future.delayed(const Duration(milliseconds: 20));
return takeScreenShot();
}
setState(() {
_hideWidget = !_hideWidget;
});
await Future.delayed(const Duration(seconds: 1));
final ui.Image image = await boundary.toImage(pixelRatio: 5);
final directory = (await getApplicationDocumentsDirectory()).path;
final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final Uint8List pngBytes = byteData!.buffer.asUint8List();
File imgFile = File('$directory/screenshot.png');
print('$directory/screenshot.png');
imgFile.writeAsBytes(pngBytes);
await Future.delayed(const Duration(seconds: 1));
setState(() {
_hideWidget = !_hideWidget;
});
}
PS: in asynchronius methods you must use FutureDelayed for properly working of SetState