Flutter (camera) does not refresh Photo Preview - ios

I am using Flutter + the camera package to create a photo and show it in a preview.
Inside the preview the user can decide if he wants to keep / use this photo - or if he wants to repeat that shot.
Problem:
When repeating the photo, the Preview-Page shows the same image as in the first try.
When using the image (sending it to an API) the user will be redirected to the page that initiated the camera call. But even there - when doing it again, the old preview is visible.
Initiating Page (Let's call it "StartPage")
SizedBox(
width: double.infinity,
child: IconButton(
icon: const Icon(Icons.camera_alt_outlined),
iconSize: 80,
color: Colors.grey,
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoPage()))
.then((value) => setState(() {}));
},
),
)
The PhotoPage shows the live camera image (Everything works fine and API call works)
class PhotoPage extends StatefulWidget {
#override
_PhotoPageState createState() => _PhotoPageState();
}
class _PhotoPageState extends State<PhotoPage> {
CameraController? cameraController;
List? cameras;
int? selectedCameraIndex;
String? imgPath;
Future initCamera(CameraDescription cameraDescription) async {
if (cameraController != null) {
await cameraController!.dispose();
}
cameraController =
CameraController(cameraDescription, ResolutionPreset.veryHigh);
cameraController!.addListener(() {
if (mounted) {
setState(() {});
}
});
if (cameraController!.value.hasError) {
print('Camera Error ${cameraController!.value.errorDescription}');
}
try {
await cameraController!.initialize();
} catch (e) {
showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
Widget cameraPreview() {
if (cameraController == null || !cameraController!.value.isInitialized) {
return Text(
'Loading',
style: TextStyle(
color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold),
);
}
return AspectRatio(
aspectRatio: cameraController!.value.aspectRatio,
child: CameraPreview(cameraController!),
);
}
Widget cameraControl(context) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.centerRight,
child: FloatingActionButton.extended(
icon: Icon(Icons.camera),
label: Text(''),
backgroundColor: Colors.green,
onPressed: () {
onCapture(context);
}))
],
//),
);
}
onCapture(context) async {
try {
var p = await getTemporaryDirectory();
var name = 'test';
var path = "${p.path}/$name.png";
XFile image = await cameraController!.takePicture();
image.saveTo(path);
await cameraController!.takePicture().then((value) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewScreen(
imgPath: path,
fileName: "$name.png",
key: UniqueKey(),
))).then((value) => setState(() {}));
});
} catch (e) {
showCameraException(e);
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
]);
availableCameras().then((value) {
cameras = value;
if (cameras!.length > 0) {
setState(() {
selectedCameraIndex = 0;
});
initCamera(cameras![selectedCameraIndex!]).then((value) {});
} else {
print('No camera available');
}
}).catchError((e) {
print('Error : ${e.code}');
});
}
#override
dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
]);
imgPath = '';
cameraController!.dispose();
PaintingBinding.instance!.imageCache!.clear();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Stack(children: <Widget>[
CameraPreview(cameraController!),
Align(
alignment: Alignment.bottomCenter,
child: Image(
image: new AssetImage(
"assets/layer.png",
),
)),
Align(
alignment: Alignment.bottomCenter,
child: Text(
"Please hold the phone in Landscape mode",
textAlign: TextAlign.center,
textScaleFactor: 1.3,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
).tr(),
),
cameraControl(context),
]),
);
}
showCameraException(e) {
String errorText = 'Error ${e.code} \nError message: ${e.description}';
}
}
So I am pushing the path of the Image to the PreviewScreen:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewScreen(
imgPath: path,
fileName: "$name.png",
key: UniqueKey(),
))).then((value) => setState(() {}));
});
My PreviewScreen looks as follows:
class PreviewScreen extends StatefulWidget {
String? imgPath;
String? fileName;
PreviewScreen(
{required this.imgPath, required this.fileName, required Key key})
: super(key: key);
#override
_PreviewScreenState createState() => _PreviewScreenState();
}
final SaveController controller = Get.put(SaveController());
class _PreviewScreenState extends State<PreviewScreen> {
/* #override
void initState() {
super.initState();
} */
#override
void dispose() {
SaveController().dispose();
_PreviewScreenState().dispose();
PaintingBinding.instance!.imageCache!.clear();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
//child: Stack(
//crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(children: [
Expanded(
flex: 2,
child: Image.file(
File(widget.imgPath!),
fit: BoxFit.cover,
),
)
]),
Align(
alignment: Alignment.bottomLeft,
child: FloatingActionButton.extended(
icon: Icon(Icons.repeat_outlined),
label: Text('Repeat').tr(),
backgroundColor: Colors.red,
onPressed: () {
widget.imgPath = '';
setState(() {});
Navigator.pop(context);
}
//Get.back();
),
),
Align(
alignment: Alignment.bottomRight,
child: FloatingActionButton.extended(
icon: Icon(Icons.check_circle_outline_sharp),
label: Text('Confirm').tr(),
backgroundColor: Colors.green,
onPressed: () {
SystemServices.savePhoto(widget.imgPath!)
.then((value) => setState(() {}));
},
),
),
],
),
);
}
Future getBytes() async {
Uint8List bytes = File(widget.imgPath!).readAsBytesSync();
// print(ByteData.view(buffer))
return ByteData.view(bytes.buffer);
}
}
The "Repeat"-Function looks as follows:
onPressed: () {
widget.imgPath = '';
setState(() {});
Navigator.pop(context);
}
Unfortunately, I really have no clue anymore.
As far as I can see it (I am a beginner in Flutter), the state is cleared and variables are empty.
Can someone tell me, why the photo in the PreviewScreen remains the same? What am I doing wrong?
Thank you very much, I really appreciate any kind of tip.

It seems like, this is the solution to for that problem:
#override
void initState() {
imageCache!.clear();
imageCache!.clearLiveImages();
super.initState();
}

Related

Flutter: how to pass an image file to another screen

Hi I need some help with passing an image that is selected from my gallery to another screen.
When I go to the 'Pick Image' screen through the grid-tiled screen, I can select an image from my gallery app. As soon as I pick one, the image pops up on the 'Pick Image' screen and it should be passed to the previous screen(grid tiled) so the image can be displayed in a grid tile.
Anyone could handle this?
The relevant part of the code is right below.
Grid Tile screen
Widget build(BuildContext context) {
return GridView.count(crossAxisCount: 4,
children: List.generate(lastDay, (index){
return GridTile(
child: Card(
child: Column(
children: <Widget>[
Text('Day ' '$index'),
SizedBox(height: 20.0,),
IconButton(
icon: Icon(Icons.add),
onPressed: (){
Navigator.push(context,
MaterialPageRoute(builder: (context) => PickImage()));
},),
],
),
),
);
}),
);
}
Pick Image Screen
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
class PickImage extends StatefulWidget {
PickImage() : super();
final String title = "Pick Image";
#override
_PickImageState createState() => _PickImageState();
}
class _PickImageState extends State<PickImage> {
Future<File> imageFile;
pickImageFromGallery(ImageSource source) {
setState(() {
imageFile = ImagePicker.pickImage(source: source);
});
}
Widget showImage() {
return FutureBuilder<File>(
future: imageFile,
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) {
return Image.file(
snapshot.data,
width: 400,
height: 400,
);
} else if (snapshot.error != null) {
return const Text(
'Error Picking Image',
textAlign: TextAlign.center,
);
} else {
return const Text(
'No Image Selected',
textAlign: TextAlign.center,
);
}
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showImage(),
RaisedButton(
child: Text("Select Image from Gallery"),
onPressed: () {
pickImageFromGallery(ImageSource.gallery);
},
),
],
),
),
);
}
}
You can copy paste run full code below
Step 1: Use Navigator.pop to return image
RaisedButton(
onPressed: () {
Navigator.pop(context, imageFileReturn);
},
child: Text('Selecct Finish, Go back '),
),
Step 2: Use Map<int, File> keep related index and image
Map<int, File> imageFileMap = {};
IconButton(
icon: Icon(Icons.add),
onPressed: () async {
imageFile = await Navigator.push(context,
MaterialPageRoute(builder: (context) => PickImage()));
imageFileMap[index] = imageFile;
setState(() {});
},
Step 3: Show image in Map
SizedBox(
height: 20.0,
child: imageFileMap[index] != null
? Image.file(
imageFileMap[index],
)
: Container()),
working demo
full code
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
class PickImage extends StatefulWidget {
PickImage() : super();
final String title = "Pick Image";
#override
_PickImageState createState() => _PickImageState();
}
class _PickImageState extends State<PickImage> {
Future<File> imageFile;
File imageFileReturn;
pickImageFromGallery(ImageSource source) {
setState(() {
imageFile = ImagePicker.pickImage(source: source);
});
}
Widget showImage() {
return FutureBuilder<File>(
future: imageFile,
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
imageFileReturn = snapshot.data;
if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) {
return Image.file(
snapshot.data,
width: 400,
height: 400,
);
} else if (snapshot.error != null) {
return const Text(
'Error Picking Image',
textAlign: TextAlign.center,
);
} else {
return const Text(
'No Image Selected',
textAlign: TextAlign.center,
);
}
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showImage(),
RaisedButton(
child: Text("Select Image from Gallery"),
onPressed: () {
pickImageFromGallery(ImageSource.gallery);
},
),
RaisedButton(
onPressed: () {
Navigator.pop(context, imageFileReturn);
},
child: Text('Selecct Finish, Go back '),
),
],
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Test(),
);
}
}
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
int lastDay = 30;
Map<int, File> imageFileMap = {};
File imageFile;
#override
Widget build(BuildContext context) {
return GridView.count(
crossAxisCount: 4,
children: List.generate(lastDay, (index) {
return GridTile(
child: Card(
child: Column(
children: <Widget>[
Text('Day ' '$index'),
SizedBox(
height: 20.0,
child: imageFileMap[index] != null
? Image.file(
imageFileMap[index],
)
: Container()),
IconButton(
icon: Icon(Icons.add),
onPressed: () async {
imageFile = await Navigator.push(context,
MaterialPageRoute(builder: (context) => PickImage()));
imageFileMap[index] = imageFile;
setState(() {});
},
),
],
),
),
);
}),
);
}
}

Flutter - setState not updating a List inside a ListView.separated

I am saving a list of favorites in my game app, I can add or remove games from the list, but on the removeFavorite method, when I use setState in "games.remove(index)" the listview.separeted doesn't update. If close and open favorite screen, the list is updated but while I am at the favorite screen it doesn't update.
class _FavoriteScreenState extends State<FavoriteScreen> {
List<dynamic> favoriteList = [];
List<Game> games = [];
#override
void initState() {
loadFavorites();
super.initState();
}
#override
Widget build(BuildContext context) {
Widget _buildListView(Game game, int index){
return InkWell(
child: Container(
height: 80,
child: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(left: 5),
child: Image.network(game.cover),
),
),
Expanded(
flex: 2,
child: Container(
child: Row(
children: <Widget>[
SizedBox(width: 15,),
Text(
game.title,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w300,
fontSize: 14
),
),
],
),
),
)
],
),
),
onLongPress: (){
_showDialog(index);
},
);
}
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
title: Text("Favorites"),
),
body: Container(
margin: EdgeInsets.fromLTRB(16, 16, 16, screenHeight > 720 ? 90 : 62),
child: ListView.separated(
separatorBuilder: (BuildContext context, int index) => Divider(color: Colors.black,),
itemCount: games.length,
itemBuilder: (context, index){
return _buildListView(games[index], index);
},
)
),
);
}
Future<File> getFile() async{
final directory = await getApplicationDocumentsDirectory();
return File("${directory.path}/favorites.json");
}
Future<String> readFavorite() async{
try{
// Le e retorna o arquivo como String
final file = await getFile();
return file.readAsString();
} catch (e){
return null;
}
}
void loadFavorites() {
readFavorite().then((data){
// Transforma o arquivo JSON numa List
favoriteList = json.decode(data);
if(favoriteList.length > 0 && favoriteList != null){
favoriteList.forEach((map){
Game game = Game(map["cover"], map["title"], map["description"], map["url"]);
setState(() {
games.add(game);
});
});
} else {
}
print(games.length);
});
}
Future<File> saveFile() async{
String data = json.encode(favoriteList);
final file = await getFile();
return file.writeAsString(data);
}
void _showDialog(int index){
showDialog(
context: context,
builder: (BuildContext context){
return AlertDialog(
content: Text("?",
style: TextStyle(fontSize: 18) ,),
actions: <Widget>[
FlatButton(
child: Text("YES"),
onPressed: (){
Navigator.of(context).pop();
removeFavorite(index);
}
),
FlatButton(
child: Text("NO"),
onPressed: (){
Navigator.of(context).pop();
}
),
],
);
}
);
}
void removeFavorite(int index){
favoriteList.forEach((m) {
Map<String, dynamic> map = m;
if (map.containsValue(games[index].title)) {
favoriteList.remove(m);
saveFile();
setState(() {
games.remove(index);
});
}
});
}
}
My bad, I replaced the remove with removeAt and it worked.
setState(() {
games.removeAt(index);
});

Maps showing blank screen when build in release mode

I am building an application where I need to use Flutter maps, everything work as expected, however if I make a build through Jankins for release mode then for some reason the maps on iOS displays blank. I have another page where the same widget is opened in a full page and there it works. My thoughts are that placing google maps in SingleChildScrolView causes the issue. Below I am attaching the source code.I have replaced the SingleChildScrolView with with list view where I pass all widgets as children but the effect is the same, the map is displayed in debug mode but when building through Jankins the map is blank , but on another page the map widget is working as expected.
Any help will be greatly appreciated as I am banging my head for hours.
Regards
class DashboardPage extends StatefulWidget {
final Model _model;
DashboardPage(this._model);
#override
_DashboardPageState createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
List<Dossier> _dossiers = List();
_DashboardPageState();
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(shrinkWrap: true, children: <Widget>[
_header(StringResources.dashboardTitle),
_mapWidget(),
_header(StringResources.myFiles),
_listWidgets()
],),
);
}
Widget _mapWidget() {
return Container(
height: 300,
child: DossierMap(
compassEnabled: false,
model: widget._model,
onDossierMapViewCreated: _onMapWidgetCreated,
onDossierInfoWindowTap: _selectedMarker,
),
);
}
Widget _listWidgets() {
return StreamBuilder<List<Dossier>>(
initialData: [],
stream: widget._model.dossierService
.loadDossiers(widget._model.loginService.token)
.catchError((e) {
if (widget._model.loggedIn) {
widget._model.forcedServerLogout();
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) {
return LoginPage(
model: widget._model,
errorText: "",
onLoggedInCallback: (context) => Navigator.of(context)
.pushReplacement(MaterialPageRoute(
builder: (context) => DossiersPage(widget._model))),
);
},
));
}
}).asStream(),
builder: (_context, snapshot) {
if (snapshot.hasData) {
_dossiers = snapshot.data;
return snapshot.data.length != 0
? _buildList(snapshot.data)
: _noDossierContentWidget();
} else if (snapshot.hasError) {
return _progressIndicator();
} else {
return _progressIndicator();
}
});
}
Widget _header(String text) {
return new Container(
decoration: new BoxDecoration(color: Color(ColorResources.darkGray)),
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 12, 0, 12),
child: Align(
alignment: Alignment.centerLeft,
child: Text(text,
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontWeight: FontWeight.w500,
fontSize: 17,
color: Colors.white))),
),
);
}
void _onMapWidgetCreated(dynamic controller) {
controller.setMarkers(_dossiers);
}
Widget _buildList(List<Dossier> dossierList) {
return Container(
color: Color(ColorResources.dividerColor),
height: 400,
child: ListView.separated(
padding: EdgeInsets.all(0.0),
separatorBuilder: (context, index) =>
Divider(color: Colors.grey.shade300, height: 1.5),
itemCount: dossierList != null ? dossierList.length : 0,
shrinkWrap: true,
physics: ScrollPhysics(),
itemBuilder: (BuildContext context, int index) => DossierListItem(
dossier: dossierList[index],
fromSearch: true,
widget: Icon(
Icons.keyboard_arrow_right,
size: 30,
color: Color(ColorResources.gray),
),
onListItemClickListener: () =>
onListItemClicked(dossierList[index]),
)));
}
void onListItemClicked(Dossier dossier) {
_selectedDossier(dossier);
}
Widget _progressIndicator() {
return Center(child: CircularProgressIndicator());
}
Widget _noDossierContentWidget() {
return Container(
color: Theme.of(context).cardColor,
child: ListTile(
title: Text(
StringResources.noOwnedFiles,
softWrap: true,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).primaryTextTheme.caption,
),
));
}
void _selectedMarker(DossierCluster cluster) async {
if (cluster.isCluster) {
Dossier selected = await showDialog(
context: context,
builder: (context) {
return AlertDialog(
contentPadding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 24.0),
title: Center(child: Text(StringResources.selectFile)),
content: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children:
dossiersFromCluster(cluster, onDossierListMarkerClick),
),
),
actions: <Widget>[
FlatButton(
child: Text(StringResources.cancel),
onPressed: () => Navigator.pop(context),
)
],
);
});
if (selected != null) _selectedDossier(selected);
} else {
_selectedDossier(cluster.getFirst);
}
}
List<Widget> dossiersFromCluster(
DossierCluster cluster, Function onDossierListMarkerClick) {
List<Widget> widgets = List();
for (int i = 0; i < cluster.size; i++) {
Dossier dossier = cluster.get(i);
widgets.add(DossierListItem(
dossier: dossier,
fromSearch: false,
widget: Container(),
onListItemClickListener: () => onDossierListMarkerClick(dossier),
));
}
return widgets;
}
void _selectedDossier(Dossier dossier) {
widget._model.setDossier(dossier);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DossierDetailsPage(widget._model)),
);
}
void _openFullSize() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => FullScreenMapPage(widget._model, _dossiers),
),
);
}
void onDossierListMarkerClick(Dossier dossier) {
widget._model.setDossier(dossier);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => DossierDetailsPage(widget._model)));
}
}

How to use SharedPreferences in Bloc Pattern?

I am trying to use shared preference in my app with the bloc pattern.
Following is my code
class PrefsStats {
final bool isMale;
final String name;
final int age;
PrefsStats(this.isMale, this.name, this.age);
}
class PrefsBloc {
final _changePrefernce = BehaviorSubject<PrefsStats>();
Function(PrefsStats) get changePrefs => _changePrefernce.sink.add;
Stream<PrefsStats> get prefrence => _changePrefernce.stream;
SharedPreferences sPrefs;
dispose(){
_changePrefernce?.close();
}
PrefsBloc(){
_loadSharedPreferences();
}
Future<void> _loadSharedPreferences() async {
sPrefs = await SharedPreferences.getInstance();
final namePref = sPrefs.getString("name") ?? "";
final malePref = sPrefs.getBool("male") ?? false;
final agePref = sPrefs.getInt("age") ?? 0;
_changePrefernce.add(PrefsStats(malePref,namePref,agePref));
}
}
final prefsBloc = PrefsBloc();
I just want to insert data using one button and get data using another button from SharedPreferences
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
prefsBloc.changePrefs(PrefsStats(true, "argo", 21));
},
child: Text("Insert Data"),
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
prefsBloc.prefrence.forEach((data){
print(data.name);
});
},
child: Text("Get Data"),
),
SizedBox(
height: 20,
),
],
)),
),
);
}
#override
void dispose() {
prefsBloc?.dispose();
super.dispose();
}
}
Whenever I close my app and reopen it again and I click get data button at the start even before inserting data, I get default values. I know I am not assigning keys at the time of setting value, which is causing the confusion of how to use shared preferences with bloc. And the other problem is whenever I set data, the code inside get data button gets called even before pressing get data which I fail to understand.
There exits two places on your code that must be fixed.
First of all, in your BloC class, your stream must Listen whenever a sink is added,
.
.
.
PrefsBloc(){
_loadSharedPreferences();
_changePrefernce.stream.listen(_newFunction);
}
void _newFunction(PrefsStats stats){
if (states != null) {
if (sPrefs != null) {
sPrefs.setString("name", states.name);
sPrefs.setInt("age", states.age);
sPrefs.setBool("male", states.isMale);
sPrefs.commit();
}
}
}
Second place is in _MyAppState class, in the build function you have to wrap Scaffold with a StreamBuilder,
class _MyHomePageState extends State<MyHomePage> {
String textAge = "";
#override
Widget build(BuildContext context) {
return MaterialApp(
home: StreamBuilder(
stream: prefsBloc.prefrence,
builder: (context, AsyncSnapshot<PrefsStats> snapshot) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Text((snapshot.data != null) ? snapshot.data.name : ""),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
prefsBloc.changePrefs(PrefsStats(
true,
textAge.toString(),
21,
));
},
child: Text("Insert Data"),
),
TextFormField(
initialValue: (snapshot.data != null) ? snapshot.data.name : "",
onFieldSubmitted: (value) {
textAge = value;
},
),
Text(textAge),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
prefsBloc.prefrence.forEach((data) {
print(data.name);
setState(() {
textAge = data.name;
});
});
},
child: Text("Get Data"),
),
SizedBox(
height: 20,
),
],
)),
);
},
));
}

AlertDialog setstate in Function/OnTap

new to flutter. I know how to set state the alert dialog, but with the need of tap to function like ()=> _createPlayer, It does not want to rebuild the alert dialog.
I wonder how to set state on alert dialog when you need to tap them.
File _image;
GestureDetector(
onTap: () => _createPlayer(),
After tap, it will display an alert dialog like this:
_createPlayer() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(32.0))),
content: Container(
height: 400,
width: 300,
child: Column(
children: <Widget>[
Text('Create Player', style: Theme
.of(context)
.textTheme
.body1),
GestureDetector(
onTap: _getImageCamera,
child: CircleAvatar(
radius: 100,
backgroundColor: Colors.white,
backgroundImage: _image != null ? FileImage(_image) : AssetImage('assets/images/undercover.png'),
),
),
],
),
),
);
});
}
_getImageCamera() async{
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = image;
});
}
I want to set state/change the image in alert dialog when selected. Any idea?
You can use StatefulBuilder for change inside dialog
showDialog(
context: context,
builder: (context) {
String contentText = "Content of Dialog";
// add StatefulBuilder to return value
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title of Dialog"),
content: Text(contentText),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
FlatButton(
onPressed: () {
setState(() {
contentText = "Changed Content of Dialog";
});
},
child: Text("Change"),
),
],
);
},
);
},
);
Create a separate Stateful Widget CustomDialog for the AlertDialog and move the _getImageCamera function _image variable inside it like this
_createPlayer() {
return CustomDialog();
}
class CustomDialog extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return CustomDialogState();
}
}
class CustomDialogState extends State<CustomDialog> {
ImageProvider _image;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(32.0))),
content: Container(
height: 400,
width: 300,
child: Column(
children: <Widget>[
Text('Create Player', style: Theme
.of(context)
.textTheme
.body1),
GestureDetector(
onTap: _getImageCamera,
child: CircleAvatar(
radius: 100,
backgroundColor: Colors.white,
backgroundImage: _image != null ? FileImage(_image) : AssetImage('assets/images/undercover.png'),
),
),
],
),
),
);
});
}
_getImageCamera() async{
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = image;
});
}
}
In order to see UI changes on showDialog, you have to create a new StatefulWidget and then work with dialog in that class. Here is the example/sample code
The most stupidest and quickest fix is:
Navigator.of(context).pop();
Then call the showDialog() again.
There will be a micro delay but works.

Resources