Flutter : How to get information about which picture in the grid has been selected? - flutter

How to get information about which picture in the grid has been selected in flutter. Please check my code!
I really need an answer to this. Please help me. I am looking forward to hearing from all of you.
Getting image and put it into a grid.
ImageEvalation.dart
class ImageEvaluation extends StatefulWidget {
#override
_ImageEvaluationState createState() => _ImageEvaluationState();
}
class _ImageEvaluationState extends State<ImageEvaluation> {
File _selectedFile;
bool _inProcess = false;
String colorCode = '#33695d';
getImage(ImageSource source, BuildContext context) async {
this.setState(() {
_inProcess = true;
});
// File image = await ImagePicker.pickImage(source: source);
final _picker = ImagePicker();
PickedFile image = await _picker.getImage(source: source);
if (image != null) {
// Remove crop attribute if we don't want to resize the image
File cropped = await ImageCropper.cropImage(
sourcePath: image.path,
aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1),
compressQuality: 100, // 100 means no compression
maxWidth: 700,
maxHeight: 700,
compressFormat: ImageCompressFormat.jpg,
androidUiSettings: AndroidUiSettings(
toolbarColor: HexColor(colorCode),
toolbarTitle: "RPS Cropper",
statusBarColor: HexColor(colorCode),
backgroundColor: Colors.white,
//toolbarWidgetColor: HexColor(colorCode),
activeControlsWidgetColor: HexColor(colorCode),
//dimmedLayerColor: HexColor(colorCode),
cropFrameColor: HexColor(colorCode),
cropGridColor: HexColor(colorCode),
),
);
this.setState(() {
_selectedFile = cropped;
_inProcess = false;
//_showDelete = true;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UploadScreen(
image: _selectedFile,
),
),
);
} else {
this.setState(() {
_inProcess = false;
});
}
}
#override
Widget build(BuildContext context) {
return _inProcess
? Loading()
: Scaffold(
body: StreamProvider<List<ImageProperty>>.value(
value: User_DatabaseService().pictureData,
child: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Text('GridView'),
PictureLinkGrid(),
Text('Image Evulation'),
MaterialButton(
onPressed: () {
getImage(ImageSource.camera, context);
},
color: Colors.deepOrange,
child: Text(
'NEXT',
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
),
);
}
}
Make a grid for my images.
PictureGrid.dart
class PictureLinkGrid extends StatefulWidget {
#override
_PictureLinkGridState createState() => _PictureLinkGridState();
}
class _PictureLinkGridState extends State<PictureLinkGrid> {
#override
Widget build(BuildContext context) {
final pictureData = Provider.of<List<ImageProperty>>(context) ?? [];
final neededPicture = [];
final demoPicture = [];
int count = 0;
// get Demo Picture
pictureData.forEach((picture) {
if (picture.title.contains('demo')) {
demoPicture.add(picture);
}
});
// get Needed Picture
pictureData.forEach((picture) {
if (picture.display_count < 10 && !picture.title.contains('demo')) {
print('${picture.title} is NOT null');
neededPicture.add(picture);
} else {
print('${picture.title} is null');
}
});
// fill in the empty picture
count = 0;
while (neededPicture.length < 9) {
neededPicture.add(demoPicture[count]);
count++;
}
return GridView.builder(
//itemCount: neededPicture.length,
itemCount: neededPicture.length,
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
print(
'Picture title in picturelink grid: ${neededPicture[index].title}');
return TouchableWebImageCard(imagePath: neededPicture[index].url);
});
}
}
Make ImageCard which can be clicked and unchecked.
TouchableWebImageCard.dart
class TouchableWebImageCard extends StatefulWidget {
String imagePath;
TouchableWebImageCard({#required this.imagePath});
//
#override
_TouchableWebImageCardState createState() =>
_TouchableWebImageCardState(imagePath);
}
class _TouchableWebImageCardState extends State<TouchableWebImageCard> {
// To pass parameters
double width;
double height;
String imagePath;
_TouchableWebImageCardState(this.imagePath);
//
bool isChecked = false;
double sigmaX = 0.0;
double sigmaY = 0.0;
double showBorder = 0;
//
checkIcon() {
return isChecked
? Center(
child: Icon(
Icons.check_circle,
color: Colors.white,
size: 50,
),
)
: Container();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Center(
child: SpinKitCircle(
color: HexColor('#33695d'),
size: 50,
),
),
Center(
child: InkWell(
child: Stack(
children: <Widget>[
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: imagePath,
),
checkIcon(),
],
),
onTap: () {
print('Image Path: $imagePath');
if (isChecked != true) {
setState(
() {
showBorder = 4.0;
isChecked = !isChecked;
},
);
} else {
setState(
() {
showBorder = 0.0;
isChecked = !isChecked;
},
);
}
},
),
),
],
);
}
}

In your TouchableWebImageCard constructor add another variable int _index;
So will know which image you have selected.
Also, the "right" way to make a constructor is:
class TouchableWebImageCard extends StatefulWidget {
TouchableWebImageCard({#required this.imagePath, this._index});
String imagePath;
int _index;

Related

PageView is consuming all gestures with embedded webview in flutter

I have an embedded web view that is nested alongside a pageview builder which controls my three js animations by sending javascript to the embedded web view.
import 'dart:async';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_museum/app/data/bloc/artifacts.dart';
import 'package:flutter_museum/app/domain/models/artifact_model.dart';
import 'package:flutter_museum/app/ui/discover/widgets/animatedCardTutorial.dart';
import 'package:flutter_museum/app/ui/discover/widgets/focusPointList.dart';
import 'package:flutter_museum/app/ui/discover/widgets/questionMarkButton.dart';
import 'package:flutter_museum/app/ui/discover/widgets/threeJSViewer.dart';
import 'package:flutter_museum/app/ui/widgets/assetOrCachedNetworkImage.dart';
import 'package:flutter_museum/app/ui/widgets/circularBackButton.dart';
import 'package:flutter_museum/app/ui/widgets/simpleVideo.dart';
import 'package:flutter_museum/app/ui/widgets/videoPlayerControllers.dart';
double deviceHeight = 0.0;
double deviceWidth = 0.0;
class ArtifactView extends StatefulWidget {
ArtifactView({
Key? key,
}) : super(key: key);
#override
State<ArtifactView> createState() => _ArtifactViewState();
}
class _ArtifactViewState extends State<ArtifactView> {
bool _fullscreen = false;
AbstractVideoPlayerController? videoPlayerController;
Timer? _restoreUiTimer;
int? startUpCount;
bool shouldShowTutorial = false;
void startFullScreen() {
if (!_fullscreen) {
setState(() {
_fullscreen = true;
_restoreUiTimer?.cancel();
_restoreUiTimer = Timer(Duration(milliseconds: 1500), endFullScreen);
});
}
}
void endFullScreen() {
setState(() {
_fullscreen = false;
});
}
void hideTutorial() {
setState(() {
shouldShowTutorial = false;
});
}
#override
void initState() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
super.initState();
}
#override
void dispose() {
SystemChrome.setPreferredOrientations(DeviceOrientation.values);
videoPlayerController?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
// hide status bar when displaying fullscreen artifact. (otherwise show status bar)
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: _fullscreen ? [] : SystemUiOverlay.values);
return BlocConsumer<ArtifactsBloc, ArtifactsState>(
listener: (context, state) {},
builder: (context, state) {
Artifact artifact = state.hasArtifact ? state.currentArtifact : Artifact.empty;
//List<FocusPoint> focusPoints = state.hasArtifact ? state.focusPoints : [];
//String modelFilePath = state.modelPath;
//bool modelIsAsset = isAssetUrl(modelFilePath);
if (videoPlayerController == null && artifact.uuid == 'ironman_artifact') {
// EasterEgg // TODO - have Kodi add the polka.mp3 file to our CDN and reference that below instead of userbob.com
videoPlayerController = createVideoPlayerController('https://userbob.com/motb/polka.mp3', useChewie: true);
videoPlayerController?.initialize();
videoPlayerController?.play();
}
// FIXME - trying to always display background sized to device's dimensions so that the background
// doesn't shift when switching to full-screen mode. The code below will prevent the background from
// shifting after the first time we've gone into full-screen mode. However, the very first time
// their will be a slight shift.
//!FIXME - We should look into the overlfow widdget to let the scaffold know we intend to let this widget be larger than the screen.
var windowSize = MediaQuery.of(context).size;
if (windowSize.height > deviceHeight) deviceHeight = windowSize.height;
if (windowSize.width > deviceWidth) deviceWidth = windowSize.width;
return Center(
child: Container(
height: deviceHeight,
width: deviceWidth,
child: Stack(
children: [
if (videoPlayerController != null)
SimpleVideo(
placeholderImage: 'asset://images/discover/washingtonrevelations.webp',
videoPlayerController: videoPlayerController!,
),
if (artifact.backgroundUrl.isNotEmpty)
Container(
height: deviceHeight,
width: deviceWidth,
child: AssetOrCachedNetworkImage(imageUrl: artifact.backgroundUrl, fit: BoxFit.cover),
),
Container(
decoration: BoxDecoration(
gradient: RadialGradient(
radius: 0.9,
colors: [
Colors.transparent,
Colors.transparent,
Colors.black38,
],
),
),
height: deviceHeight,
width: deviceWidth,
),
Listener(
onPointerDown: (PointerDownEvent e) {
startFullScreen();
},
child: GestureDetector(
onPanEnd: ((details) {
print('ended');
}),
child: ThreeJSViewer(
modelFilePath: state.modelPath,
initScale: artifact.cameraZoom.toInt(),
autoRotateSpeed: 2,
state: state,
),
),
),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: EdgeInsets.only(top: 35),
child: CircularBackButton(
outterPadding: EdgeInsets.fromLTRB(10, 10, 0, 0),
onTap: () {
AutoRouter.of(context).pop();
},
),
),
),
AnimatedPositioned(
bottom: 60 - (_fullscreen ? 250 : 0.0),
duration: Duration(milliseconds: 300),
child: GestureDetector(
child: FocusPointList(
state: state,
),
),
),
],
),
),
);
},
);
}
}
finally here is my WebView plus widget
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_museum/app/data/bloc/artifact/artifacts_state.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:webview_flutter_plus/webview_flutter_plus.dart';
// ignore: must_be_immutable
class ThreeJSViewer extends StatefulWidget {
final String? modelFilePath;
final String? modelURLPath;
final double? autoRotateSpeed;
final int initScale;
final ArtifactsState state;
final bool? debug;
final void Function(PointerMoveEvent)? onPointerMove;
ThreeJSViewer({
Key? key,
this.modelFilePath,
this.onPointerMove,
this.modelURLPath,
required this.initScale,
this.autoRotateSpeed,
required this.state,
this.debug,
}) : super(key: key);
#override
State<ThreeJSViewer> createState() => _ThreeJSViewerState();
}
class _ThreeJSViewerState extends State<ThreeJSViewer> {
int progress = 0;
WebViewPlusController? controller;
bool isRendered = false;
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
if (snapshot.data == true) {
return Stack(
children: [
if (progress < 100 && isRendered == true)
Align(
alignment: Alignment.center,
child: Container(
height: 100,
width: 100,
child: CircularProgressIndicator(
value: progress.toDouble(),
),
),
),
WebViewPlus(
initialCookies: [],
gestureNavigationEnabled: true,
zoomEnabled: false,
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>[
new Factory<OneSequenceGestureRecognizer>(
() {
print('GestureRecognizer created');
return new EagerGestureRecognizer();
},
),
].toSet(),
backgroundColor: Colors.transparent,
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: ({
JavascriptChannel(
name: 'JavascriptChannel',
onMessageReceived: (message) {
if (message == "200") {
setState(() {
isRendered = true;
});
}
log(message.message);
},
)
}),
onProgress: (_progress) {
setState(() {
progress = _progress;
});
},
onWebViewCreated: (_controller) {
controller = _controller;
_controller.loadUrl("assets/renderer/index.html");
},
onPageFinished: (value) {
Future.delayed(Duration(milliseconds: 100), () {
this.widget.state.controller = controller?.webViewController;
this.widget.state.controller!.runJavascript(
'init("${this.widget.modelFilePath ?? this.widget.modelURLPath}", ${this.widget.initScale},${this.widget.initScale},${this.widget.initScale}, ${this.widget.autoRotateSpeed ?? 2}, ${this.widget.debug ?? false})',
);
});
},
onPageStarted: (value) {
log(value);
},
onWebResourceError: (value) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error loading model. Please make sure you have internet connection.'),
),
);
log(value.description);
},
),
],
);
} else {
return Center(
child: Container(
child: DefaultTextStyle(
style: TextStyle(color: Colors.white, fontSize: 25),
child: Text(
"no internet connection",
),
),
),
);
}
},
future: InternetConnectionChecker().hasConnection,
);
}
}
My WebView is able to accept all gesture events when I initially rotate or zoom the three js model, but when I swipe a card on the pageview builder it consumes whatever gesture event for the duration of the widget lifetime.
finally here are the pageview cards
import 'package:flutter/material.dart';
import 'package:flutter_museum/app/data/bloc/artifact/artifacts_state.dart';
import 'package:flutter_museum/app/domain/models.dart';
import 'package:flutter_museum/app/ui/discover/views/focusPointView.dart';
import 'package:flutter_museum/app/ui/discover/widgets/focusPointCard.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_museum/app/data/bloc/artifacts.dart';
class FocusPointList extends StatefulWidget {
final ArtifactsState state;
const FocusPointList({Key? key, required this.state}) : super(key: key);
#override
State<FocusPointList> createState() => _FocusPointListState();
}
class _FocusPointListState extends State<FocusPointList> {
#override
Widget build(BuildContext context) {
int _centeredFocusPointIndex = 0;
ArtifactsState _state = this.widget.state;
List<FocusPoint> focusPoints = _state.hasArtifact ? _state.focusPoints : [];
List artifactFocusPointsList = focusPoints
.map(
(fp) => FocusPointCard(
publisher: fp.publisher ?? '',
subtitle: fp.subtitle ?? '',
title: fp.title,
imageUrl: fp.thumbnailImageUrl,
externalLink: fp.externalLink,
cardOnTap: () => _handleTapOnCard(context: context, focusPoint: fp),
),
)
.toList();
return Container(
height: 160,
width: MediaQuery.of(context).size.width,
child: PageView.builder(
itemCount: artifactFocusPointsList.length,
controller: PageController(viewportFraction: 0.75),
onPageChanged: (int index) {
setState(() {
_centeredFocusPointIndex = index;
FocusPoint afp = focusPoints[index];
bool isPointsEmpty = afp.x + afp.y + afp.z != 0;
if (index < focusPoints.length - 1 && isPointsEmpty) {
_centeredFocusPointIndex = index;
_state.controller?.runJavascript('tweenCamera(${afp.x}, ${afp.y}, ${afp.z}, 2000);');
}
});
},
itemBuilder: (_, index) {
return Transform.scale(
scale: index == _centeredFocusPointIndex ? 1 : 0.9,
child: artifactFocusPointsList[index],
);
},
),
);
}
void _handleTapOnCard({required BuildContext context, required FocusPoint focusPoint}) {
if (focusPoint.externalLink != null) {
launch(focusPoint.externalLink!);
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FocusPointView(
title: focusPoint.title,
subtitle: focusPoint.subtitle ?? '',
publisher: focusPoint.publisher ?? '',
imageUrl: focusPoint.detailImageUrl ?? '',
description: focusPoint.description ?? '',
),
),
);
}
}
}

ImagePicker with Bloc - Flutter

How to add a stream with a picture(ImagePicker) in the bloc architecture, which can be selected from the phone, what should the widget look like?
My example is without validation whether it is to be included?
How should I work in a bloc along with the avatar photo?
I do not know how to approach it and what steps would be taken when it comes to both validation of such a photo, if possible, and the use of stream with bloc, any help is very welcome.
class ProfileView extends StatefulWidget {
const ProfileView({Key? key}) : super(key: key);
#override
_ProfileViewState createState() => _ProfileViewState();
static Route route() {
return MaterialPageRoute<void>(builder: (_) => ProfileView());
}
}
class _ProfileViewState extends State<ProfileView> {
final bloc = Bloc();
#override
Widget build(BuildContext context) {
return Scaffold(
body: _profilePage(context),
);
}
Widget _profilePage(BuildContext context) {
return ColorfulSafeArea(
color: orange,
child: Center(
child: Column(
children: [
_changeAvatarButton(context),
SizedBox(height: 15),
_usernameTile(),
SizedBox(height: 5),
_cityTile(),
SizedBox(height: 60),
],
),
),
);
// });
}
// Profile avatar
Widget _avatar() {
return CircleAvatar(
radius: 83,
backgroundColor: orange,
child: CircleAvatar(
backgroundColor: Colors.white,
radius: 80,
child: Icon(personIcon, size: 60, color: orange),
),
);
}
Widget _changeAvatarButton(BuildContext context) {
return Column(
children: [
CircleAvatar(
radius: 83,
backgroundColor: orange,
child: _image == null
? _avatar()
: ClipRRect(
borderRadius: BorderRadius.circular(83),
child: Image.file(
_image!,
height: 160,
// Change the size up or down accordingly border radius
width: 160,
// Change the size up or down accordingly border radius
fit: BoxFit.cover,
)),
),
CustomButtonText(
onPressed: () {
_showPicker(context);
},
title: changePhoto,
textColor: teal),
],
);
}
File? _image;
final picker = ImagePicker();
Future getImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.gallery, maxWidth: 1800, maxHeight: 1800);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print(getImageText);
}
});
}
Future getCameraImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 1800,
maxHeight: 1800,
);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print(getImageText);
}
});
}
void _showPicker(BuildContext context) {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(photoIcon),
title: Text(showPickerPhoto),
onTap: () async {
await getImage();
Navigator.of(context).pop();
}),
ListTile(
leading: Icon(cameraIcon),
title: Text(showPickerCamera),
onTap: () async {
await getCameraImage();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
Widget _usernameTile() {
return StreamBuilder(
stream: bloc.name,
builder: (context, snapshot) {
return CustomTextField(
title: 'Name',
obscureText: false,
colour: Colors.black,
keyboardType: TextInputType.name,
labelText: labelTextUsername,
onChanged: bloc.changeName,
errorText: snapshot.error != null ? 'invalid name' : null
// onChanged: (newValue) {
// bloc.changeName(newValue);
// },
);
});
}
Widget _cityTile() {
return StreamBuilder(
stream: bloc.city,
builder: (context, snapshot) {
return CustomTextField(
title: 'City',
obscureText: false,
colour: Colors.black,
keyboardType: TextInputType.name,
labelText: labelTextCity,
onChanged: bloc.changeCity,
errorText: snapshot.error != null ? 'invalid city' : null
);
});}
}
Validators looks in this way:
class Validators {
static final RegExp _nameRegExp = RegExp(
r'^(?=.*[a-z])[A-Za-z ]{3,}$',
);
final validateName =
StreamTransformer<String, String>.fromHandlers(handleData: (name, sink) {
if (name.contains(_nameRegExp)) {
sink.add(name);
} else {
sink.addError('Enter a valid name');
}
});
static final RegExp _cityRegExp = RegExp(
r'^[a-zA-Z]+(?:[\s-][a-zA-Z]+)*$',
);
final validateCity =
StreamTransformer<String, String>.fromHandlers(handleData: (city, sink) {
if (city.contains(_cityRegExp)) {
sink.add(city);
} else {
sink.addError('Enter a valid city');
}
});
static final RegExp _avatarRegExp = RegExp(
r'/.*\.(gif|jpe?g|bmp|png)$/igm',
);
final validateAvatar =
StreamTransformer<String, String>.fromHandlers(handleData: (avatar, sink) {
if (avatar.contains(_avatarRegExp)) {
sink.add(avatar);
} else {
sink.addError('Enter a valid avatar photo');
}
});
}
and Bloc:
import 'dart:async';
import 'dart:io';
import 'validators.dart';
class Bloc extends Validators {
//instances
//
final _avatarPath = StreamController<File>();
final _name = StreamController<String>();
final _city = StreamController<String>();
//add data stream
Stream<File> get avatarPath => _avatarPath.stream;
Stream<String> get name => _name.stream.transform(validateName);
Stream<String> get city => _city.stream.transform(validateCity);
// change data
Function(File) get changeAvatarPath => _avatarPath.sink.add;
Function(String) get changeName => _name.sink.add;
Function(String) get changeCity => _city.sink.add;
//for cleanup
void dispose() {
_avatarPath.close();
_name.close();
_city.close();
}
}
// bloc.changeName---> bloc.nameController.sin.add
final bloc = new Bloc();

How do I select individual image for a favorite icon with onPressed ()?

Here is the entire code. I simply want the heart icon to change color when selected as favorite, then push the saved favorite item to a saved favorites page. I have no idea how to do it with stream builder.
ERROR is : In this code, when I click on a image icon, all image's icon get
selected as favorite.
class CloudAlbum extends StatefulWidget {
static const routeName = '/album';
#override
_CloudAlbumState createState() => _CloudAlbumState();
}
class _CloudAlbumState extends State<CloudAlbum> {
#override
void initState() {
super.initState();
_getCurrentUser();
}
final FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseUser loggedInUser ;
_getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser();
try {
if (user != null) {
setState(() {
loggedInUser = user;
print(loggedInUser.email);
print(loggedInUser.uid);
final email = loggedInUser.email;
return email;
});
}
} catch(e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
String email = "";
setState(() {
email = loggedInUser.email;
});
//final imgid = ModalRoute.of(context).settings.arguments as String;
final favImg = Provider.of<FavImg>(context, listen: false);
var users = Firestore.instance.collection('abc').document('xyz').collection(email).snapshots();
return StreamBuilder(
stream: users,
builder: (ctx, streamSnapshot) {
if (streamSnapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
final docs = streamSnapshot.data.documents;
//List<bool> _isFavorited = List<bool>.generate(docs.length, (_) => false);
print(docs);
return GridView.builder(
itemCount: docs.length,
itemBuilder: (ctx, index) =>
Container(
padding: EdgeInsets.all(5),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: GridTile(
child: GestureDetector(
onTap: () {
// Navigator.of(context).pushNamed(
// FullImage.routeName);
},
child: Hero(
tag: docs[index]['id'],
child: FadeInImage(
placeholder: AssetImage('assets/images/placeholder.png'),
image: NetworkImage(docs[index]['imgurl']),
fit: BoxFit.cover,
),
),
),
footer: GridTileBar(
backgroundColor: Colors.black26,
leading:
Consumer<FavImg>(
builder: (ctx, favImg, _) =>
// IconButton(
// onPressed: () => setState(()
// => _isFavorited[index]= !_isFavorited[index]),
// icon: _isFavorited[index]
// ? Icon(Icons.star)
// : Icon(Icons.star_border),
// ),
IconButton(
icon: Icon(
favImg.isFavorite ? Icons.favorite : Icons.favorite_border,
size: 35.0,
),
color: Colors.red,
onPressed: () {
favImg.toggleFavoriteStatus(
docs[index]['id'],
);
},
),
),
),
),
),
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 2,
crossAxisSpacing: 1,
mainAxisSpacing: 5,
),
);
}
);
}
}
favimg.dart
class FavImg with ChangeNotifier {
final String imageUrl;
final String id;
bool isFavorite;
FavImg({
#required this.imageUrl,
#required this.id,
this.isFavorite = false,
});
void toggleFavoriteStatus(String id) {
isFavorite = !isFavorite;
notifyListeners();
}
}
ERROR is : In this code, when i click on a image icon, all image's icon get selected as favorite.

How do I pass data from a stateful widget to state ensuring widget data is available?

I'm passing data from a stateful widget, and I access it like in this example (widget.variable)
https://stackoverflow.com/a/50818870/806009
However, occasionally it throws an error (about 1 in 20) for a line in this comparison
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The method '>' was called on null.
Receiver: null
Tried calling: >(10)
if (widget.x > 10){...}
It seems that widget.x is not known at this time. Should I use initState to ensure that value is "ready"?
Such as
#override
void initState() {
super.initState();
this.x = widget.x
}
Full Code
class PlayerSelection extends StatefulWidget {
final int teamId;
final int leagueId;
final League.League league;
final String className;
List<PlayerObj> playersListOfClass;
final int index;
final int remaining;
PlayerSelection({Key key, #required this.teamId, this.leagueId, this.league, this.className, this.playersListOfClass, this.index, this.remaining}) : super(key: key);
#override
_PlayerSelection createState() => _PlayerSelection();
}
class _PlayerSelection extends State<PlayerSelection> {
var playerWidgets = <Widget>[];
List<PlayerObj> selectedPlayers = [];
List<PlayerObj> playerList = [];
PlayerObj draftedPlayer;
List<PlayerClass> playerClassList = [];
bool _isFavorited = false;
Modal modal = new Modal();
int lineupWeek = 0;
int lineupSize = 0;
String intervalLabel = '';
bool _is_full = false;
bool _is_locked = false;
int remaining = 0;
var currentColor = Colors.black;
var rejectedPlayerId;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
resizeToAvoidBottomPadding: false,
appBar: globals.MyAppBar(
leading: IconButton(icon: Icon(Icons.close),
onPressed: (){
Navigator.pop(context, {'player': null,'index': this.widget.index});
}), // go to league route,),
title: Text(widget.className)
),
body: Container(
child: Column(children: [Expanded(child: ListView(children: _getLineup(this.widget.playersListOfClass))),]),
),
);
}
List<Widget>_getLineup(playerList) {
List<Widget> widgets = [];
var index = 0;
playerList.forEach((player) =>
widgets.add(
Padding(
padding: const EdgeInsets.symmetric(horizontal:16.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(width: 1.0, color: Colors.grey.withOpacity(0.3)),
),
),
child: new ListTile(
leading: GestureDetector(
onTap: (){
if(!_is_full) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
Players.PlayerDetail(playerId: player.playerId,
leagueId: widget.leagueId,
playerName: player.playerName,
playerBio: player.playerBio)),
);
}
},
child: ClipOval(
child: _playerPicWidget(player)
),
),
title: GestureDetector(
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
Players.PlayerDetail(playerId: player.playerId,
leagueId: widget.leagueId,
playerName: player.playerName,
playerBio: player.playerBio)),
);
},
child: _playerNameWidget(player)
),
trailing: _trailingWidget(player),
onTap: () => player.playerPrice <= widget.remaining ? Navigator.pop(context, {'player': player,'index': this.widget.index}) : null,
// return player back
),
),
)
)
);
return widgets;
}
Widget _playerNameWidget(player){
if(this._is_full && !this.selectedPlayers.contains(player)){ //show disabled selection
return Opacity(opacity:.25, child:Text("${player.playerName}"));
}
else {
if(this.widget.league.hasBudget){ // can afford player, not full
if(player.playerPrice <= widget.remaining || this.selectedPlayers.contains(player)){
return Text("${player.playerName}");
}
else { // can't afford player, not full
return Opacity(opacity:.25, child:Text("${player.playerName}"));
}
}
else { // slot still open
return Text("${player.playerName}");
}
}
}
Widget _playerPicWidget(player){
if(player == this.draftedPlayer){
return Opacity(opacity: .25, child: Image.network('${player.playerImageUrl}',
fit: BoxFit.scaleDown,
height: 45,
width: 45,
));
}
else {
if(player.playerPrice <= widget.remaining || this.selectedPlayers.contains(player)){
return Image.network('${player.playerImageUrl}',
fit: BoxFit.scaleDown,
height: 45,
width: 45,
);
}
}
}
Widget _trailingWidget(player){
List<Widget> tWidgets;
double playerOpacity = 1;
if(player.playerPrice > widget.remaining){
playerOpacity = .25;
}
tWidgets = [
Padding(padding: const EdgeInsets.symmetric(horizontal:10.0),
child: Opacity(opacity:playerOpacity, child:Text("\$${globals.commaFormat.format(player.playerPrice)}")),
), Opacity(opacity: playerOpacity, child: Icon(Icons.add))];
return Row(mainAxisSize: MainAxisSize.min, children: tWidgets);
}
}
The issue was a data issue unrelated to the passing of data.

Flutter dont reload a image when i take a picture

i'm studying flutter and im trying to create a person register. In this page i hava a normal register with basic data and person photo.
But im having some issue with update a Image, when i take the picture the component Image dont change to taked image;
I tried find some controller to Image or Image Provider but unsuccessful.
This is my code:
class _RegisterForm extends State<RegisterForm> {
final TextEditingController _textEditingControllerPassword =
new TextEditingController();
final TextEditingController _textEditingControllerComparePassword =
new TextEditingController();
final TextEditingController _textEditingControllerEmail =
new TextEditingController();
final TextEditingController _textEditingControllerFullName =
new TextEditingController();
final _formKey = GlobalKey<FormState>();
User _user = null;
Image _image = null;
#override
void setState(VoidCallback fn) {
super.initState();
this._user = new User(
_textEditingControllerPassword.text,
_textEditingControllerFullName.text,
_textEditingControllerEmail.text,
_textEditingControllerComparePassword.text,
_image,
);
this.build(context);
}
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.fromLTRB(23, 0, 23, 0),
child: Column(children: <Widget>[
GestureDetector(
child: CircleAvatarImage(_image),
onTap: getImage,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Tire sua foto!"),
),
InputString(
"Como gostaria ",
hint: "Marianx Silva",
maxLenght: 100,
controller: this._textEditingControllerFullName,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
InputString(
"E-mail",
maxLenght: 100,
controller: this._textEditingControllerEmail,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
InputString(
"Senha",
controller: this._textEditingControllerPassword,
maxLenght: 12,
obscureText: true,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
InputString(
"Confime a senha",
controller: this._textEditingControllerComparePassword,
maxLenght: 12,
obscureText: true,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
RegisterUserInFirebaseButton(
"Continuar",
_formKey,
_user,
// edgeInsets: EdgeInsets.fromLTRB(0, 40, 0, 0),
),
]),
));
}
Future getImage() async {
File image = await ImagePicker.pickImage(source: ImageSource.camera);
this._image = Image.file(image);
setState(() {
_user = null;
});
}
}
This is my "CircleAvatarImage" component:
import 'package:flutter/material.dart';
const AssetImage _defaultImage = AssetImage("assets/images/default_image.png");
class CircleAvatarImage extends StatefulWidget {
Image image;
CircleAvatarImage(this.image);
#override
State<StatefulWidget> createState() {
return __CircleAvatarImageState();
}
}
class __CircleAvatarImageState extends State<CircleAvatarImage> {
AnimationController _controller;
#override
Widget build(BuildContext context) {
return CircleAvatar(
radius: 62,
backgroundColor: Colors.blue,
child: CircleAvatar(
radius: 60.0,
child: Padding(
padding: const EdgeInsets.only(top: 90),
child: Icon(
Icons.camera_enhance,
color: Colors.white,
),
),
backgroundImage:
widget.image == null ? _defaultImage : widget.image.image,
),
);
}
}
You didn't use setState. So, there's no way Widget would no that it has to udpate. Try :
setState() => this._image = Image.file(image);