I am trying to create a Button Widget to add a photo in Flutter. I want the button to be generic, since my intention is that when I call it through the view, I can pass the parameter belonging to the data model where I want to save the photo as an argument.
The button would have this form:
Where when selecting the photo, what is seen in the image should be replaced by the photo itself, occupying the available space.
The problem is that after selecting the photo, and verifying that there is information stored in the variable that contains it, the container of the photo remains unchanged, that is, as if nothing had been added.
Here I show you how it is done.
class AddPhotoButton extends StatelessWidget{
late XFile _pickedFile;
final ImagePicker _picker = ImagePicker();
late Uint8List image = Uint8List(0);
AddPhotoButton({Key? key,
required this.image
});
// carga la imagen de la galeria
Future<void> getImage() async {
//setState(ViewState.Busy);
_pickedFile = (await _picker.pickImage(source: ImageSource.gallery))!;
image = (_pickedFile != null ? await _pickedFile.readAsBytes() : null)!;
//setState(ViewState.Idle);
}
@override
Widget build(BuildContext context) {
// usa el model de CreateMoment para poder cargar la foto y enviarla
return GestureDetector(
// funcionalidad del boton
onTap: getImage,
// aspecto del boton
child:SizedBox(
height: MediaQuery.of(context).size.width - 24 * 2,
child: image.isEmpty
// si no hay imagen cargada
? DottedBorder(
borderType: BorderType.RRect,
color: Colors.green,
strokeWidth: 3,
radius: const Radius.circular(10),
// primer elemento longitud y segundo el espacio
dashPattern: const [6, 6],
child: const Center(
child: SizedBox(
child: Icon(
Icons.add,
color: Colors.grey,
size: 40,
),
),
),
)
// si hay imagen cargada que las muestre
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
fit: BoxFit.fill,
image: MemoryImage(image),
),
),
),
),
);
}
}
And this is how I make the call to the Widget in the view:
Padding(
padding: const EdgeInsets.only(top: 30),
child: AddPhotoButton(image:model.GoodSilageImg),
)
Where "image: model.GoodSilageImg" is the variable belonging to my data model where I want to save the image.
EDIT: I forgot to comment, but the data model where the image is saved in principle is defined like this (in case it was of any use)
class VisualEvaluationModel extends BaseModel
{
List<int> list = 'xxx'.codeUnits;
late Uint8List GoodSilageImg;
VisualEvaluationModel()
{
GoodSilageImg = Uint8List(0);
}
}
EDIT 2: Trying to use a statefull widget, to use the setState and be able to restart the view I have the following code:
class AddPhotoButton extends StatefulWidget{
late XFile _pickedFile;
final ImagePicker _picker = ImagePicker();
late Uint8List image = Uint8List(0);
AddPhotoButton({Key? key,
required this.image
});
// carga la imagen del momento de la galeria
Future<void> getImage() async {
//setState(ViewState.Busy);
_pickedFile = (await _picker.pickImage(source: ImageSource.gallery))!;
// puede ser que se no seleccione imagen al final
image = (_pickedFile != null ? await _pickedFile.readAsBytes() : null)!;
//setState(ViewState.Idle);
}
@override @override
State<StatefulWidget> createState() {
// usa el model de CreateMoment para poder cargar la foto y enviarla
return GestureDetector(
// funcionalidad del boton
onTap: getImage,
// aspecto del boton
child: SizedBox(
height: MediaQuery
.of(context)
.size
.width - 24 * 2,
child: image.isEmpty
// si no hay imagen cargada
? DottedBorder(
borderType: BorderType.RRect,
color: Colors.green,
strokeWidth: 3,
radius: const Radius.circular(10),
// primer elemento longitud y segundo el espacio
dashPattern: const [6, 6],
child: const Center(
child: SizedBox(
child: Icon(
Icons.add,
color: Colors.grey,
size: 40,
),
),
),
)
// si hay imagen cargada que las muestre
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
fit: BoxFit.fill,
image: MemoryImage(image),
),
),
),
),
);
}
}
But this gives me problems with the Gesture Detector, which cannot be inside a create state according to the error. I know this might be a silly bug but I'm new to this.
I have solved it, effectively, as @diegoveloper commented, the Statefull Widget was badly created.
It also has an added plus and that is that to pass arguments we must call
Which has had to be previously established in the main class. I leave you with the corrected example: