How to show a widget when the marker is clicked on in gmap flutter? - flutter

I want to show a widget with the latlong info and a button when the marker is placed on the map.or clicked on marker.
this is my code to handle the markers
Future<void> addMarker(
LatLng mLatLng, String mTitle, String mDescription) async {
final Uint8List markerIcon =
await getBytesFromAsset('assets/images/icons/pin.png', 100);
setState(() {
_markers.clear();
_markers.add(Marker(
markerId:
MarkerId((mTitle + "_" + _markers.length.toString()).toString()),
position: mLatLng,
infoWindow: InfoWindow(
title: mTitle,
snippet: mDescription,
),
icon: BitmapDescriptor.fromBytes(
markerIcon), //BitmapDescriptor.defaultMarker,
));
});
}
Future<void> _handleTap(LatLng tappedPoint) async {
print(tappedPoint);
final words = await api
.convertTo3wa(Coordinates(tappedPoint.latitude, tappedPoint.longitude))
.language('en')
.execute();
print(words.data()!.words);
LatLng mLatLng = tappedPoint;
String mTitle = '///${words.data()!.words}';
String mDescription =
'Coordinates: ${words.data()!.coordinates.lat}, ${words.data()!.coordinates.lng},\nNearest Place: ${words.data()!.nearestPlace}';
setState(() {
_markers.clear();
if (words.isSuccessful()) {
addMarker(mLatLng, mTitle, mDescription);
getPillInfowindow(mLatLng, mTitle, mDescription);
//_customInfoWindowController.hideInfoWindow!();
} else {
print(words.error());
}
});
}
and the widget i want shown when marker is clicked on is this
import 'package:flutter/material.dart';
import 'package:mymapp/screens/home_page.dart';
Widget getPillInfowindow(mLatLng, mTitle, mDescription) {
return Positioned(
bottom: 100, right: 0, left: 0,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.all(20),
height: 70,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(50)),
boxShadow: <BoxShadow>[
BoxShadow(
blurRadius: 20,
offset: Offset.zero,
color: Colors.grey.withOpacity(0.5))
]),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 10),
width: 50,
height: 50,
child: ClipOval(
child: Image.asset('assets/images/icons/pin2.png',
fit: BoxFit.cover))),
// first widget
Expanded(
child: Container(
margin: EdgeInsets.only(left: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('title:${mTitle}', //${mTitle}',
style: TextStyle(
color: Colors
.green)), //currentlySelectedPin.labelColor)),
Text(
'Latitude, Longitude: ${mLatLng}',
style: TextStyle(fontSize: 12, color: Colors.grey)),
Text(
'Desc: ${mDescription}', //
style: TextStyle(fontSize: 12, color: Colors.grey))
], // end of Column Widgets
), // end of Column
),
), // second widget
],
),
),
),
); // end of Container
}
but somehow this doesn't work the way I want it to. What's wrong here?
Sorry if there's mistakes here, I'm a beginner in flutter

Future<void> _handleTap(LatLng tappedPoint) async {
// Your existing code to get the marker information
// ...
setState(() {
_markers.clear();
if (words.isSuccessful()) {
addMarker(mLatLng, mTitle, mDescription);
_pillInfoWindow = getPillInfowindow(mLatLng, mTitle, mDescription); // Update the _pillInfoWindow variable with the new marker information
} else {
print(words.error());
}
});
}
then
Stack(
children: [
GoogleMap(
// ... your existing GoogleMap widget code ...
onMapCreated: (GoogleMapController controller) {
_mapController = controller;
},
onTap: _handleTap,
markers: _markers,
),
if (_pillInfoWindow != null) _pillInfoWindow!, // Add the _pillInfoWindow widget to the Stack
],
)

Related

The list I created appears on all rows of the expansionpanellist

I'm new to Flutter and I'm having problems with expansion panel lists. Firstly, let me explain what I'm trying to do. I have a map application that gets the user's current location when they press the "start" button and displays the distance, date and time when the journey is finished and the "finish" button is pressed. Then, this information is stored in an expansion panel list on a separate "history" page.
However, I also have a third button called "add location". This button appears when the "start" button is pressed and allows the user to add their current location while the journey is ongoing. These locations are added to a list called "tripLocations" within my code. Then, when the "finish" button is pressed, all of this information is added to the expansion panel list.
My problem is that every time a journey is finished, the "tripLocations" list is displayed in the expansion panel list and shows all of the previous locations. However, I want each row in the expansion panel list to represent a single journey and only show the locations that were added during that journey. Essentially, there should be a "tripLocations" list for each row in the expansion panel list and it should be reset every time a new journey is started.
The following codes belong to my button.dart page.
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:material_dialogs/shared/types.dart';
import 'package:material_dialogs/widgets/buttons/icon_outline_button.dart';
import 'package:yolumukaydet/constant/constant.dart';
import 'package:latlong/latlong.dart';
import 'package:material_dialogs/material_dialogs.dart';
import 'package:lottie/lottie.dart';
import 'package:material_dialogs/widgets/buttons/icon_button.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geocoding_platform_interface/geocoding_platform_interface.dart';
class GradientText extends StatelessWidget {
const GradientText(
this.text, {
required this.gradient,
this.style,
});
final String text;
final TextStyle? style;
final Gradient gradient;
#override
Widget build(BuildContext context) {
return ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => gradient.createShader(
Rect.fromLTWH(0, 0, bounds.width, bounds.height),
),
child: Text(text, style: style),
);
}
}// texte gradient atamak için yapıldı
class StartHistory{
String city1;
String district1;
bool isExpanded;
StartHistory({
required this.city1,
required this.district1,
this.isExpanded = false,});
}//varış yeri konumu gösterme
class StartHistoryData {
static List<StartHistory> starthistory = [];
static void addStartHistory(String city1, String district1) {
starthistory.add(StartHistory(city1: city1, district1: district1));
}
}//varış yeri konumu gösterme
class TripLocation {
String address;
TripLocation({
required this.address,
});
}
class History {
String distance;
String date;
String time;
String city;
String district;
bool isExpanded;
History({
required this.distance,
required this.date,
required this.time,
required this.city,
required this.district,
this.isExpanded = false,
});
}
class HistoryData {
static List<History> history = [];
static List<TripLocation> tripLocations = [];
static void addHistory(String distance, String date, String time, String city, String district,) {
history.add(History(distance: distance, date: date, time: time, city: city, district: district,));
}
static void addTripLocation(TripLocation tripLocation) {
tripLocations.add(tripLocation);
}
}//mesafe ,tarih ve saat bilgileri
class Location {
final double latitude;
final double longitude;
final String note;
Location({
required this.latitude,
required this.longitude,
required this.note,
});
}//Konum Ekle butonu için konum alıyor
TextEditingController _noteController = TextEditingController();
List<Map<String, String>> _locations = [];
class ImageButton extends StatefulWidget {
#override
_ImageButtonState createState() => _ImageButtonState();
}
class _ImageButtonState extends State<ImageButton>with TickerProviderStateMixin {
bool _isStarted = false;
bool _isStopped = true;
void _getCurrentLocation() async {
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
setState(() {
if (position != null) {
_currentPosition = position;
}
});
}
late Position _startPosition;
late Position _currentPosition;
double _distance = 0.0;
String _time = "";
Geolocator geolocator = Geolocator();
int _selectedIndex = 0;
final List<String> imageList = [
'assets/images/pwb3.png',
'assets/images/pwb4.png',
];
void _onPressed1() {
setState(() {
_selectedIndex = (_selectedIndex + 1) % imageList.length;
});
// buraya butona tıklama olayında yapmanız gereken diğer işlemleri ekleyebilirsiniz
}
late AnimationController _controller;
bool isOpened = false;
#override
void initState() {
_getCurrentLocation();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
);
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
child: Align(
child: Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(left:160,top: 540.0,right:150),
width: 350.0,
height: 350.0,
child: FloatingActionButton(
child: Image.asset(
imageList[_selectedIndex],
height: 350.0,
width: 350.0,
),
onPressed: () {
setState(() {
_onPressed1();
isOpened = !isOpened;
if (isOpened) {
_controller.forward();
} else {
_controller.reverse();
}
});
},
),
),
Visibility(
visible: _isStarted,
child: Align(
alignment: Alignment.topRight,
child: Container(
width: 75.0,
height: 85.0,
margin: EdgeInsets.only(top: 540.0,right:50),
child: ScaleTransition(
scale: _controller,
child: FloatingActionButton(
backgroundColor: Constant.green,
child: Icon(Icons.add,size: 40.0,color: Constant.darkgrey,),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
String noteText = '';
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Container(
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Konumunuz Eklenecek',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
SizedBox(height: 10.0),
Divider(
color: Colors.black,
height: 1.0,
),
SizedBox(height: 10.0),
Text(
'Eklediğiniz konum ve notlar geçmiş sayfasına kaydedilecektir.',
style: TextStyle(
fontSize: 8.0,
),
),
SizedBox(height: 10.0),
TextField(
controller: _noteController,
decoration: InputDecoration(hintText: 'Notunuzu Ekleyin'),
),
SizedBox(height: 10.0),
ElevatedButton(
onPressed: () async {
_getCurrentLocation();
//BURASI İL VE İLÇE KONUM ADLARINI ALIYOR VE CİTY İLE DİSTİRCT DEĞİŞKENİN ATIYOR
List<Placemark> placemarks = await placemarkFromCoordinates(_currentPosition.latitude, _currentPosition.longitude);
String _address = '${placemarks[0].administrativeArea}, ${placemarks[1].subAdministrativeArea}';
var tripLocation = TripLocation(address: _address);
HistoryData.addTripLocation(tripLocation);
Navigator.pop(context);
setState(() {});
print("tripLocation");
},
child: Text('Tamam'),
),
],
),
),
);
},
);
},
),
),
),
)),// KONUM EKLE BUTTONU
Visibility(
visible: _isStarted,
child: Align(
alignment: Alignment.topLeft,
child: Container(
width: 75.0,
height: 75.0,
margin: EdgeInsets.only(left:50,top: 540.0,),
child: ScaleTransition(
scale: _controller,
child: FloatingActionButton(
backgroundColor: Constant.green,
child: Icon(Icons.stop,size:40.0,color: Constant.darkgrey,),
onPressed: () async {
setState(() {
_isStopped = true;
_isStarted = false;
});
//BURASI İL VE İLÇE KONUM ADLARINI ALIYOR VE CİTY İLE DİSTİRCT DEĞİŞKENİN ATIYOR
List<Placemark> placemarks = await placemarkFromCoordinates(_currentPosition.latitude, _currentPosition.longitude);
String? city = placemarks.isNotEmpty ? placemarks[0].administrativeArea: '';
String? district = placemarks.isNotEmpty ? placemarks[1].subAdministrativeArea : '';
//
//
_currentPosition = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
final Distance distance = new Distance();
var km = distance.as(
LengthUnit.Kilometer,
new LatLng(_startPosition.latitude, _startPosition.longitude),
new LatLng(_currentPosition.latitude,_currentPosition.longitude));
setState(() {
_time = DateTime.now().toString().substring(0, 19);
});
setState(() {
_distance = km as double;
});
showDialog(
context: context,
builder: (context) {
return AlertDialog(
backgroundColor: Constant.darkgrey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
title: Container(
alignment: Alignment.center,
child: Text('Mesafe Bilgisi',
style: TextStyle(
color: Colors.white
),)),
content: Container(
height: 400,
width: 400,
decoration: BoxDecoration(
color: Constant.darkgrey,
borderRadius: BorderRadius.circular(50.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GradientText(
'$_distance km',
style: const TextStyle(fontSize: 80,
fontFamily: 'digital',
),
gradient: LinearGradient(colors: [
Colors.white54,
Colors.white70,
]),
),
Text("Tarih ${DateTime.now().toString().split(' ').first} / SAAT ${DateTime.now().toString().split(' ').last.substring(0, 8)}",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.white
),
),
Text(
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.white
),"$city / $district"),
Container(
width:350,
height: 45,
child: FloatingActionButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(5),
bottomLeft: Radius.circular(5),
bottomRight: Radius.circular(5),
),
),
backgroundColor: Constant.green,
child: Text("TAMAM",
style: TextStyle(
color: Constant.darkgrey,
),),
onPressed: () {
HistoryData.addHistory("$_distance km", "${DateTime.now().toString().split(' ').first}", "${DateTime.now().toString().split(' ').last.substring(0, 8)}","$city","$district",);
Navigator.of(context).pop();
},
),
),
],
),
),
);
},
);
},
),
),
),
),
),// STOP BUTTONU
Visibility(
visible: _isStopped,
child: Align(
alignment: Alignment.topCenter,
child: Container(
width: 75.0,
height: 75.0,
margin: EdgeInsets.only(top: 440.0),
child: ScaleTransition(
scale: _controller,
child: FloatingActionButton(
backgroundColor: Constant.green,
child: Icon(Icons.start,size:40.0,color: Constant.darkgrey,),
onPressed: () async {
List<Placemark> placemarks = await placemarkFromCoordinates(_currentPosition.latitude, _currentPosition.longitude);
String? city1 = placemarks.isNotEmpty ? placemarks[0].administrativeArea: '';
String? district1 = placemarks.isNotEmpty ? placemarks[1].subAdministrativeArea : '';
StartHistoryData.addStartHistory("$city1","$district1");
setState(() {
_isStarted = true;
_isStopped = false;
});
_startPosition = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
},
),
),
),
),) // START BUTTONU
],
),
),
);
}
}
These codes belong to my historypage.dart file
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:yolumukaydet/appbar.dart';
import 'package:yolumukaydet/constant/constant.dart';
import 'package:yolumukaydet/menu.dart';
import 'package:yolumukaydet/navigator_bar.dart';
import 'package:flutter/material.dart';
import 'package:yolumukaydet/button.dart';
class GecmisPage extends StatefulWidget {
#override
_GecmisPageState createState() => _GecmisPageState();
}
class _GecmisPageState extends State<GecmisPage> {
List<Map<String, dynamic>> _locations = [];
void _removeItem(String date) {
int indexToRemove = HistoryData.history.indexWhere((element) =>
element.date == date);
setState(() {
HistoryData.history.removeAt(indexToRemove);
});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 600),
content: Text('#$date tarihli bilginiz silindi.')));
} // delete tuşu
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Constant.darkgrey,
appBar: AppBarPage(),
body: Column(
children: [
ExpansionPanelList(
expansionCallback: (int index, bool isExpanded) {
setState(() {
HistoryData.history[index].isExpanded = !isExpanded;
});
},
children: List.generate(
HistoryData.history.length,
(index) {
return ExpansionPanel(
backgroundColor: Constant.opacgrey,
headerBuilder: (BuildContext context, bool isExpanded) {
return ListTile(
title: Text("Tarih: " + HistoryData.history[index].date + " - " + HistoryData.history[index].city + "/" + HistoryData.history[index].district),
leading: IconButton(
onPressed: () => _removeItem(HistoryData.history[index].date),
icon: const Icon(
Icons.delete,
color: Constant.green,
),
),
);
},
body: Container(
height: 500,
width: double.infinity,
color: Constant.opacgrey,
child: Container(
height: 250,
width: double.infinity,
decoration: BoxDecoration(),//boş bırakıldı
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Mesafe :", style: TextStyle(fontSize: 18.0)),
Text("${HistoryData.history[index].distance}",
style: TextStyle(fontSize: 18.0)),
Text(" / ", style: TextStyle(fontSize: 18.0)),
Text("Saat :", style: TextStyle(fontSize: 18.0)),
Text("${HistoryData.history[index].time}",
style: TextStyle(fontSize: 18.0)),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Varış Yeri :", style: TextStyle(fontSize: 18.0)),
Text("${StartHistoryData.starthistory[index].city1}",
style: TextStyle(fontSize: 18.0)),
Text(" / ", style: TextStyle(fontSize: 18.0)),
Text("${StartHistoryData.starthistory[index].district1}",
style: TextStyle(fontSize: 18.0)),
],
),
),
Container(
height: 400,
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.black,width: 2)
),
child:
ListView.builder(
itemCount: HistoryData.tripLocations.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(HistoryData.tripLocations[index].address),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
HistoryData.tripLocations.removeAt(index);
});
},
),
);
},
)
),
],
),
),
),
),
isExpanded: HistoryData.history[index].isExpanded,
);
},
),
),
],
),
);
}
}
Where should I make the corrections here? I'm waiting for your help, thank you.

Looking up a deactivated widget's ancestor is unsafe.Flutter integaration test

type here
iam new to flutter and trying to learn test integration test package and i have come around this error.
The following assertion was thrown while finalizing the widget
tree:
Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer
stable.
To safely refer to a widget's ancestor in its dispose() method,
save a reference to the ancestor by calling
dependOnInheritedWidgetOfExactType() in the widget's
didChangeDependencies() method.
and to the little understanding that i have this is the class throwing that error
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'package:wildai/helper/check_connectivity.dart';
import 'package:wildai/helper/common_methods.dart';
import 'package:wildai/helper/screen_config.dart';
import 'package:wildai/helper/toast_helper.dart';
import 'package:wildai/redux/actions.dart';
import 'package:wildai/redux/app_state.dart';
import 'package:wildai/redux/middleware/checkin_calls/checkin_update_get_data_call.dart';
import 'package:wildai/redux/middleware/homescreen_calls/update_single_view_calls.dart';
import 'package:wildai/src/models/dashboard/dashboard_model.dart';
import 'package:wildai/src/widgets/buttons/custom_radio_button.dart';
import 'package:wildai/src/widgets/custom_margins.dart';
import 'package:wildai/src/widgets/my_bottom_sheet.dart';
import 'package:wildai/utils/custom_alert.dart';
import 'package:wildai/utils/my_custom_text_theme.dart';
import 'package:wildai/helper/http_wrapper_custom.dart' as http;
import 'package:wildai/utils/my_redesign_icons.dart';
class EditCheckInOverlayPage extends StatefulWidget {
EditCheckInOverlayPage(this.title, this.avaiableCheckinItem,
this.updateCheckinsUrl, this.keyValue,
{Key key, this.showLoading = false, this.checkInRequestBody})
: super(key: key);
final String title;
final Map avaiableCheckinItem;
final String keyValue;
final String updateCheckinsUrl;
final Map checkInRequestBody;
bool showLoading;
\_EditCheckInOverlayPageState createState() =\> \_EditCheckInOverlayPageState();
}
class \_EditCheckInOverlayPageState extends State\<EditCheckInOverlayPage\> {
String micIconString = 'assets/icons/microphone.png';
Map responseBody = {'show_checkins': {}};
List\<AvaiableCheckinItemModel\> avaiableCheckinItems;
DateTime delayTime = DateTime.now();
final FlutterSecureStorage storage = new FlutterSecureStorage();
final store = StoreProvider.of\<AppState\>(SizeConfig.rootPagecOntext);
#override
void initState() {
super.initState();
avaiableCheckinItems = widget.avaiableCheckinItem\[widget.keyValue\];
List\<int\> requiredIntList = \[\];
for (var i = 0; i \< avaiableCheckinItems.length; i++) {
if (avaiableCheckinItems\[i\].require) {
requiredIntList.add(i);
}
}
for (int index in requiredIntList) {
var temp = avaiableCheckinItems\[index\];
avaiableCheckinItems.removeAt(index);
avaiableCheckinItems.insert(0, temp);
}
}
#override
void dispose() {
super.dispose();
if (mounted && !responseBody\['show_checkins'\].isEmpty) {
updateAvaiableCheckInsResponse();
print('///////////////////////////////');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Align(
alignment: Alignment.bottomCenter,
child: MyBottomModelSheet.titleSheet(
title: 'Edit ${widget.title} Check-ins',
height: 530,
onClose: () {
Navigator.pop(context);
},
body: sortDetailsContainer()),
),
);
}
Widget titleWidget() {
return Container(
decoration: BoxDecoration(color: Colors.white, boxShadow: \[
BoxShadow(
blurRadius: 25,
color: SizeConfig.primaryTextColour.withOpacity(.3),
)
\]),
child: Row(
children: \[
Expanded(
child: Padding(
padding: cmargin(top: 31, left: 30, right: 30),
child: Text(
'Edit ${widget.title} Check-Ins'.toUpperCase(),
style: MyCustomTextStyles().buttonTextSmall.copyWith(
color: SizeConfig.primaryTextColour.withOpacity(.4),
),
),
),
)
\],
),
);
}
Widget searchbarWidget() {
final \_formKey = GlobalKey\<FormState\>();
return Container(
color: Colors.white,
child: Padding(
padding: cmargin(left: 25, right: 25, bottom: 20, top: 22),
child: Container(
height: HelperMethods().getMyDynamicHeight(36),
decoration: BoxDecoration(
color: Color(0xff767680).withOpacity(.12),
borderRadius: BorderRadius.circular(10)),
child: Row(
children: \[
Padding(
padding: cmargin(left: 8, right: 7.37),
child: Container(
height: HelperMethods().getMyDynamicHeight(15.78),
width: HelperMethods().getMyDynamicWidth(15.63),
child: Icon(
MyAwesomeIcons.loupe,
color: Color(0xff8E8E93),
size: HelperMethods().getMyDynamicWidth(15.63),
),
),
),
Expanded(
child: Form(
key: \_formKey,
child: TextFormField(
onSaved: (String \_value) {
if (!\_formKey.currentState.validate() ||
\_value.isEmpty) {
return;
}
print(\_value);
},
style: MyCustomTextStyles().body.copyWith(
color: SizeConfig.primaryTextColour, height: 1),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Search',
hintStyle: MyCustomTextStyles().body.copyWith(
color: Color(0xff3C3C43).withOpacity(.6),
height: 1.1,
),
),
),
),
),
Padding(
padding: cmargin(right: 9.63),
child: Container(
height: HelperMethods().getMyDynamicHeight(16.37),
width: HelperMethods().getMyDynamicWidth(11),
child: Image.asset(
micIconString,
color: Color(0xff8E8E93),
fit: BoxFit.contain,
),
),
),
\],
),
),
));
}
Widget closeButton() {
return Container(
color: Colors.transparent,
height: HelperMethods().getMyDynamicWidth(55),
width: SizeConfig.screenWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: \[
Padding(
padding: cmargin(right: 30, bottom: 25),
child: InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () {
Navigator.pop(context);
},
child: Container(
decoration: BoxDecoration(
color: Colors.black.withOpacity(.2),
shape: BoxShape.circle,
),
height: HelperMethods().getMyDynamicWidth(30),
width: HelperMethods().getMyDynamicWidth(30),
child: Icon(
MyAwesomeIcons.close,
key: Key("close_button"),
size: HelperMethods().getMyDynamicWidth(30),
)),
),
)
\],
),
);
}
Widget sortDetailsContainer() {
return Expanded(
child: ModalProgressHUD(
inAsyncCall: false,
color: Colors.transparent,
child:
Container(
width: SizeConfig.screenWidth,
color: Colors.white,
child: Padding(
padding: cmargin(),
child: ListView(
padding: cmargin(),
children: List.generate(
avaiableCheckinItems.length + 1,
(index) => index == avaiableCheckinItems.length
? Container(
height: 50,
)
: InkWell(
key: Key(avaiableCheckinItems[index].displayName),
onTap: () {
//delayTime = DateTime.now();
if (avaiableCheckinItems[index].require &&
avaiableCheckinItems[index].selected) {
return;
}
avaiableCheckinItems[index].selected =
!avaiableCheckinItems[index].selected;
addToResponseBody(avaiableCheckinItems[index]);
setState(() {});
},
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: SizeConfig.primaryTextColour
.withOpacity(.4),
width: HelperMethods()
.getMyDynamicFontSize(.35)))),
child: Padding(
padding: cmargin(
left: 30, top: 20, bottom: 20, right: 30),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width:
HelperMethods().getMyDynamicWidth(244),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Flexible(
child: Text(
avaiableCheckinItems[index]
.displayName,
style: MyCustomTextStyles()
.formText
.copyWith(
color: SizeConfig
.primaryTextColour,
height: 1),
),
),
avaiableCheckinItems[index].require
? Text(
' (required)',
style: MyCustomTextStyles()
.labelSmall
.copyWith(
color: SizeConfig
.primaryTextColour),
)
: Container()
],
),
),
Opacity(
opacity: avaiableCheckinItems[index]
.require &&
avaiableCheckinItems[index].selected
? .2
: 1,
child: CustomRadioButton(
onTap: (value) {
if (avaiableCheckinItems[index]
.require &&
avaiableCheckinItems[index]
.selected) {
return;
}
avaiableCheckinItems[index].selected =
!avaiableCheckinItems[index]
.selected;
addToResponseBody(
avaiableCheckinItems[index]);
setState(() {});
},
selected:
avaiableCheckinItems[index].selected,
),
)
],
),
),
),
)),
),
),
),
),
);
}
addToResponseBody(AvaiableCheckinItemModel checkInItem) {
if (responseBody\['show_checkins'\].containsKey(checkInItem.modelName)) {
responseBody\['show_checkins'\]\[checkInItem.modelName\]
\[checkInItem.dbVariable\] = checkInItem.selected;
} else {
responseBody\['show_checkins'\]\[checkInItem.modelName\] = {
checkInItem.dbVariable: checkInItem.selected
};
}
print(responseBody);
return;
}
updateAvaiableCheckInsResponse() {
Conn().connectivityResult().then((conn) async {
if (conn) {
final store = StoreProvider.of\<AppState\>(SizeConfig.rootPagecOntext);
String body = json.encode(responseBody);
responseBody = {'show_checkins': {}};
String token = await storage.read(key: "wildUserToken");
DashboardCheckInsModel oldCheckins =
store.state.dashboardDataModel.checkins;
store.state.dashboardDataModel.checkins = DashboardCheckInsModel();
store.dispatch(SetDashboardObject(store.state.dashboardDataModel));
if (widget.showLoading) {
await \_createCheckins(oldCheckins);
}
final response =
await http.post(Uri.encodeFull(widget.updateCheckinsUrl),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
"Authorization": "Token $token"
},
body: body);
if (response.statusCode == 200) {
store.state.dashboardDataModel.checkins = oldCheckins;
store.dispatch(updateDashboardCheckinCall(forceRefresh: true));
} else if (response.statusCode == 400 || response.statusCode == 500) {
var res = json.decode(response.body);
store.dispatch(SetDashboardObject(store.state.dashboardDataModel));
String msg = res\['details'\];
CustomAlert().showCustomAlert(
context, "Oops! Something went wrong. ", msg, AlertType.info);
} else {
store.dispatch(SetDashboardObject(store.state.dashboardDataModel));
// throw Exception("failed to load calendar");
}
} else {
ShowMyToastHelper().showCheckConnectionToast(context, 2);
}
});
}
Future \_createCheckins(DashboardCheckInsModel dashboardCheckInsModel) async {
await Conn().connectivityResult().then((bool conn) async {
if (conn) {
String body = json.encode(widget.checkInRequestBody);
String token = await storage.read(key: "wildUserToken");
final response = await http.post(
Uri.encodeFull(dashboardCheckInsModel.endpoints.submitCheckin.url),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
"Authorization": "Token $token"
},
body: body);
if (response.statusCode == 200) {
store.dispatch(checkInsUpdateGetDataCall(silenty: true));
}
} else {
ShowMyToastHelper().showCheckConnectionToast(context, 2);
}
});
}
}
the problem is the script runs and performs its actions but the test fails.
any guidance would be appreciated.if there is anymore information needed for clarification i'll be happy to provide it.

Flutter - Image.memory not refreshing after source change

I have a page that allows users to upload documents (as images). I have structured my page in a way that for each document type that can be uploaded a Document_Upload widget is used to reduce the amount of repeated code.
On initial load I use a FutureBuilder to get all the documents the user has already uploaded from our REST Api and then populate each Document_Upload widget with the relevant data.
On successful upload our REST Api returns the new image back to the Flutter app as a Byte Array so it can be displayed.
The problem I am currently facing is that no matter what I try the image widget (Image.memory) does not display the new image, it just stays on the old one.
I have tried almost everything I can think of/ find online to resolve this issue, including:
Calling setState({}); after updating the imageString variable - I can see the widget flash but it remains on the original image.
Using a function to callback to the parent widget to rebuild the entire child widget tree - same result as setState, all the widgets flash, but no update.
Calling imageCache.clear() & imageCache.clearLiveImages() before updating the imageString.
Using CircleAvatar instead of Image.memory.
Rebuilding the Image widget by calling new Image.memory() inside the setState call.
I am starting to question if this is an issue related to Image.memory itself, however, using Image.File / Image.network is not an option with our current requirement.
Refreshing the page manually causes the new image to show up.
My code is as follows:
documents_page.dart
class DocumentsPage extends StatefulWidget {
#override
_DocumentsPageState createState() => _DocumentsPageState();
}
class _DocumentsPageState extends State<DocumentsPage>
with SingleTickerProviderStateMixin {
Future<Personal> _getUserDocuments;
Personal _documents;
#override
void didChangeDependencies() {
super.didChangeDependencies();
_getUserDocuments = sl<AccountProvider>().getUserDocuments();
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SafeArea(
child: Center(
child: Padding(
padding: EdgeInsets.all(20),
child: Container(
constraints: BoxConstraints(maxWidth: 1300),
child: buildFutureBuilder(context)),
)),
),
);
}
Widget buildFutureBuilder(BuildContext context) {
var screenSize = MediaQuery.of(context).size;
return FutureBuilder<Personal>(
future: _getUserDocuments,
builder: (context, AsyncSnapshot<Personal> snapshot) {
if (!snapshot.hasData) {
return Text("Loading");
} else {
if (snapshot.data == null) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
_documents = snapshot.data;
return Column(
children: [
SizedBox(height: 20.0),
Text(
"DOCUMENTS",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: AppColors.navy),
),
Container(
constraints: BoxConstraints(maxWidth: 250),
child: Divider(
color: AppColors.darkBlue,
height: 20,
),
),
Container(
margin: EdgeInsets.only(top: 5.0, bottom: 5.0),
child: Text(
"These documents are required in order to verify you as a user",
style: TextStyle(fontSize: 14))),
Container(
margin: EdgeInsets.only(bottom: 25.0),
child: Text("View our Privacy Policy",
style: TextStyle(fontSize: 14))),
Container(
child: screenSize.width < 768
? Column(
children: [
DocumentUpload(
imageType: "ID",
imageString: _documents.id),
DocumentUpload(
imageType: "Drivers License Front",
imageString: _documents.driversLicenseFront,
),
DocumentUpload(
imageType: "Drivers License Back",
imageString: _documents.driversLicenseBack,
)
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
DocumentUpload(
imageType: "ID",
imageString: _documents.id),
DocumentUpload(
imageType: "Drivers License Front",
imageString: _documents.driversLicenseFront,
),
DocumentUpload(
imageType: "Drivers License Back",
imageString: _documents.driversLicenseBack,
),
])),
Container(
child: screenSize.width < 768
? Container()
: Padding(
padding:
EdgeInsets.only(top: 10.0, bottom: 10.0))),
Container(
child: screenSize.width < 768
? Column(
children: [
DocumentUpload(
imageType: "Selfie",
imageString: _documents.selfie,
),
DocumentUpload(
imageType: "Proof of Residence",
imageString: _documents.proofOfResidence,
),
Container(width: 325)
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
DocumentUpload(
imageType: "Selfie",
imageString: _documents.selfie,
),
DocumentUpload(
imageType: "Proof of Residence",
imageString: _documents.proofOfResidence,
),
Container(width: 325)
])),
],
);
}
}
});
}
}
document_upload.dart
class DocumentUpload extends StatefulWidget {
final String imageType;
final String imageString;
const DocumentUpload({this.imageType, this.imageString});
#override
_DocumentUploadState createState() => _DocumentUploadState();
}
class _DocumentUploadState extends State<DocumentUpload> {
String _imageType;
String _imageString;
bool uploadPressed = false;
Image _imageWidget;
#override
Widget build(BuildContext context) {
setState(() {
_imageType = widget.imageType;
_imageString = widget.imageString;
_imageWidget =
new Image.memory(base64Decode(_imageString), fit: BoxFit.fill);
});
return Container(
constraints: BoxConstraints(maxWidth: 325),
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
boxShadow: [
new BoxShadow(
color: AppColors.lightGrey,
blurRadius: 5.0,
offset: Offset(0.0, 3.0),
),
],
),
child: Card(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Column(children: <Widget>[
Padding(padding: EdgeInsets.only(top: 5.0)),
Row(
//ROW 1
children: <Widget>[
Expanded(
child: Text(
_imageType,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColors.darkBlue),
),
),
],
),
Row(
//ROW 2
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(left: 5.0, bottom: 5.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: _imageWidget,
)),
),
Consumer<AccountProvider>(
builder: (context, provider, child) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding:
EdgeInsets.only(top: 5.0, bottom: 5.0),
child: Icon(Icons.star,
size: 20, color: AppColors.darkBlue)),
Padding(
padding:
EdgeInsets.only(top: 5.0, bottom: 5.0),
child: Text('Drag file here or',
textAlign: TextAlign.center)),
Padding(
padding:
EdgeInsets.only(top: 5.0, bottom: 5.0),
child: DynamicGreyButton(
title: uploadPressed
? "Uploading ..."
: "Browse",
onPressed: () async {
FilePickerResult result =
await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
'jpg',
'jpeg',
'png'
]);
if (result != null) {
uploadPressed = true;
Uint8List file =
result.files.single.bytes;
String fileType =
result.files.single.extension;
await provider
.doUploadDocument(
_imageType, file, fileType)
.then((uploadResult) {
if (uploadResult == null ||
uploadResult == '') {
showToast(
"Document failed to upload");
return;
} else {
showToast("Document uploaded",
Colors.green, "#66BB6A");
uploadPressed = false;
_imageString = uploadResult;
setState(() {});
}
});
} else {
// User canceled the picker
uploadPressed = false;
}
},
))
]));
})
],
),
])));
}
}
Image Upload HTTP Call
#override
Future uploadDocuments(DocumentsUpload model) async {
final response = await client.post(
Uri.https(appConfig.baseUrl, "/api/Account/PostDocuments_Flutter"),
body: jsonEncode(model.toJson()),
headers: <String, String>{
'Content-Type': 'application/json'
});
if (response.statusCode == 200) {
var data = json.decode(response.body);
return data;
} else {
return "";
}
}
EDIT: Attached GIF of current behaviour.
I am pretty much out of ideas at this point, any help would be greatly appreciated.
Came up with a solution.
I created a second variable to hold the new image string and showed an entirely new image widget once the second variable had value.
String _newImage;
In the success of the upload...
_newImage = uploadResult;
setState(() {});
Image widget...
child: (_newImage == null || _newImage == '')
? new Image.memory(base64Decode(_imageString), fit: BoxFit.fill)
: new Image.memory(base64Decode(_newImage), fit: BoxFit.fill)
Not a very elegant solution, but it's a solution, but also not necessarily the answer as to why the original issue was there.

How to solve: type 'List<dynamic>' is not a subtype of type 'String' [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
I want to update image from listofTaskNotApprove class which it will pass the object of documentsnapshot into the EditTaskNotApprove. Before I update the image, I need to display specific of image where the user will be select specific info from listofTaskNotApprove. The problem is how to display the current index of image into the new screen?
ListOfTaskNotAccepted class.
import 'package:carousel_pro/carousel_pro.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:fyp/screen/RecordOfficer/EditTaskNotApprove.dart';
import 'package:fyp/shared/Loading.dart';
import 'package:google_fonts/google_fonts.dart';
class ListOfTaskNotAccepted extends StatefulWidget {
#override
_ListOfTaskNotAcceptedState createState() => _ListOfTaskNotAcceptedState();
}
final FirebaseAuth auth = FirebaseAuth.instance;
Stream<QuerySnapshot> getUser(BuildContext context) async* {
final FirebaseUser rd = await auth.currentUser();
yield* Firestore.instance.collection("Task").where('uid',isEqualTo: rd.uid).where("verified", isEqualTo: 'TidakSah').snapshots();
}
class _ListOfTaskNotAcceptedState extends State<ListOfTaskNotAccepted> {
List<NetworkImage> _listOfImages = <NetworkImage>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Aduan Tidak Diterima"),
backgroundColor: Colors.redAccent,
),
body: Container(
child: StreamBuilder(
stream: getUser(context),
builder: (context, snapshot){
if (snapshot.hasError || !snapshot.hasData) {
return Loading();
} else{
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index){
DocumentSnapshot da = snapshot.data.documents[index];
_listOfImages =[];
for(int i =0; i <da['url'].length; i++){
_listOfImages.add(NetworkImage(da['url'][i]));
}
return Card(
child:ListTile(
title: Container(
alignment: Alignment.centerLeft,
child: Column(
children: <Widget>[
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Sumber Aduan: ", style: GoogleFonts.asap(fontWeight: FontWeight.bold)),
Text(da['sumberAduan'], style: GoogleFonts.asap(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Nombor Aduan: ", style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
Text(da['noAduan'], style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Lokasi: ", style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
Text(da['kawasan'] + " " + da['naJalan'], style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Kategori: ", style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
Text(da['kategori'], style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
],
),
),
Column(
children: [
Container(
margin: EdgeInsets.all(10.0),
height: 200,
decoration: BoxDecoration(
color: Colors.white
),
width: MediaQuery.of(context).size.width,
child: Carousel(
boxFit: BoxFit.cover,
images: _listOfImages,
autoplay: false,
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomCenter,
animationCurve: Curves.fastLinearToSlowEaseIn,
animationDuration: Duration(milliseconds: 2000),
),
)
],
)
],
),
),
subtitle: Container(
child: Column(
children: [
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Catatan: ", style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
Text(da['comments'], style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
],
),
),
],
),
),
onTap: () {Navigator.push(context, MaterialPageRoute(builder: (context) => EditTask(da:da)));}
)
);
});
}
}),
)
);
}
}
Here is EditTask class which I need to display current index of image that selected by user.
import 'package:carousel_pro/carousel_pro.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class EditTask extends StatefulWidget {
final DocumentSnapshot da;
const EditTask({Key key, this.da}) : super(key: key);
#override
_EditTaskState createState() => _EditTaskState(da);
}
class _EditTaskState extends State<EditTask> {
DocumentSnapshot da;
_EditTaskState(DocumentSnapshot da){
this.da = da;
}
TextEditingController _noAduan;
TextEditingController _sumberAduan;
TextEditingController _kategori;
DateTime myDateTime = DateTime.now();
#override
void initState(){
super.initState();
_noAduan = TextEditingController(text: widget.da.data['noAduan']);
_sumberAduan =TextEditingController(text: widget.da.data['sumberAduan']);
_kategori = TextEditingController(text: widget.da.data['kategori']);
myDateTime = (da.data['date']).toDate();
_listOfImages = NetworkImage(da.data['url']) as List<NetworkImage>; // this line show the error
}
List <String> sumber = <String> ['Sistem Aduan MBPJ', 'Sistem Aduan Waze', 'Sistem Aduan Utiliti'];
List <String> kate = <String> ['Segera', 'Pembaikan Biasa'];
String kategori;
String sumberAduan;
List <NetworkImage> _listOfImages = <NetworkImage>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Kemaskini Aduan"),
backgroundColor: Colors.redAccent,
),
body: Container(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(height: 10.0),
TextFormField(
decoration:InputDecoration(
hintText: myDateTime.toString(),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5))),
onChanged: (value){
setState(() {
myDateTime = value as DateTime;
print(myDateTime);
});
},
),
SizedBox(height: 10.0),
TextFormField(
decoration:InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5))),
controller: _noAduan,
),
SizedBox(height: 10.0),
DropdownButtonFormField(
hint:Text(widget.da.data['sumberAduan']),
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_contact_calendar),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5))),
isExpanded: true,
value: sumberAduan,
onChanged: (newValue) {
setState(() {
sumberAduan = newValue;
_sumberAduan.text = sumberAduan;
});
},
items: sumber.map((sum){
return DropdownMenuItem(
value: sum,
child: new Text(sum),
);
}).toList(),
),
SizedBox(height: 10.0),
DropdownButtonFormField(
hint:Text(widget.da.data['kategori']),
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_contact_calendar),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5))),
isExpanded: true,
value: kategori,
onChanged: (newValue) {
setState(() {
kategori = newValue;
_kategori.text = kategori;
});
},
items: kate.map((ka){
return DropdownMenuItem(
value: ka,
child: new Text(ka),
);
}).toList(),
),
Container(
margin: EdgeInsets.all(10.0),
height: 200,
decoration: BoxDecoration(
color: Colors.white
),
width: MediaQuery.of(context).size.width,
child: Carousel(
boxFit: BoxFit.cover,
autoplay: false,
//images: _listOfImages,
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomCenter,
animationCurve: Curves.fastLinearToSlowEaseIn,
animationDuration: Duration(milliseconds: 2000),
),
)
],
),
),
)
);
}
}
the image that need to display for update image
This is how I want to display image in class EditTask when the user want to update information from ListOfTaskNotApprove
The error show that "type 'List' is not a subtype of type 'String'"
Can someone help me? because I had tried many method to solve this problem but it didn't work for me.
You say:
_listOfImages = NetworkImage(da.data['url']) as List<NetworkImage>; // this line show the error
Yes, you can't cast a NetworkImage to a List<NetworkImage>. You probably meant:
_listOfImages = [ NetworkImage(da.data['url']) ] as List<NetworkImage>;
The thing is your are getting a list of url's from Firebase storage which are Strings but you are adding this strings into a list of type Network Image which is wrong. As a list of string cannot be converted to a list of Network Image.
There are 2 ways to resolve this-
Change your list type to List and then wherever you show this image use
list data as an argument for Network Image.
List<String> urls=new List();
//suppose list is not empty
....
return NetworkImage(urls[i]);
....
While adding url's to your list add an Network Image object and directly use the list item while showing images.
List<NetworkImage> list=new List();
list.add(NetworkImage('some url'));
....
return list[i];
....

Flutter Stateful Widget used across Multiple Screens getting Rebuilt

ive created the below Multiselect Chip Widget its using Provider and Listening for changes to the list
the widget creates a List of Choice Chips that allows multiple choice chips to be chosen
class MultiSelectChip extends StatefulWidget {
final Function(List<String>) onSelectionChanged;
MultiSelectChip({this.onSelectionChanged});
#override
_MultiSelectChipState createState() => _MultiSelectChipState();
}
class _MultiSelectChipState extends State<MultiSelectChip> {
List<String> selected = List();
List<Clinic> clinicList = List();
#override
void didChangeDependencies() {
final list = Provider.of<ClinicProvider>(context).clinics;
final clinic = Clinic(
id: null,
name: "All Clinics",
city: null,
suburb: null,
postcode: null,
prate: null,
udarate: null,
goal: null,
uid: null);
clinicList.add(clinic);
selected.add(clinicList[0].name);
list.forEach((clinic) => clinicList.add(clinic));
super.didChangeDependencies();
}
_buildList() {
List<Widget> choices = List();
clinicList.forEach((item) {
choices.add(Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5.0),
child: ChoiceChip(
key: Key("${item.name}"),
shape: selected.contains(item.name)
? RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(0),
),
)
: RoundedRectangleBorder(
side: BorderSide(
color: Color.fromRGBO(46, 54, 143, 1), width: 1.0),
borderRadius: BorderRadius.circular(0.0),
),
label: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(item.name),
),
onSelected: (value) {
setState(() {
selected.contains(item.name)
? selected.remove(item.name)
: selected.add(item.name);
widget.onSelectionChanged(selected);
});
},
selected: selected.contains(item.name),
selectedColor: Color.fromRGBO(46, 54, 143, 1),
labelStyle:
selected.contains(item.name) ? kChipActive : kChipInActive,
backgroundColor: Colors.transparent,
),
));
});
return choices;
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 8.0, top: 5.0, bottom: 5.0),
child: SizedBox(
height: 50,
width: double.infinity,
child: ListView(
scrollDirection: Axis.horizontal,
children: _buildList(),
),
),
);
}
}
when i click from this Log screen and goto the NewLog screen and Pop Back to the Log Screen
class LogScreen extends StatefulWidget {
static const String id = 'logscreen';
#override
_LogScreenState createState() => _LogScreenState();
}
class _LogScreenState extends State<LogScreen> {
MonthSelector selectedMonth;
List<String> selectedItems = List();
static DateTime now = DateTime.now();
static DateTime end = DateTime(now.year, now.month + 1, 0);
static DateTime start = DateTime(now.year, now.month, 1);
MonthSelector currentMonth = MonthSelector(
monthName: DateFormat("MMMM").format(now),
monthStart: start,
monthEnd: end);
void refreshData(MonthSelector selector) async {
await Provider.of<LogProvider>(context, listen: false)
.getLogs(selector.monthStart, selector.monthEnd);
await Provider.of<LogProvider>(context, listen: false)
.loadTreatments(selector.monthStart, selector.monthEnd);
}
#override
Widget build(BuildContext context) {
final List<LogSummary> list = Provider.of<LogProvider>(context).summary;
final List<FlSpot> chartData = Provider.of<LogProvider>(context).spots;
return Container(
color: Color.fromRGBO(246, 246, 246, 1),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 15,
),
RawMaterialButton(
onPressed: () {
Navigator.pushNamed(context, NewLogScreen.id);
},
constraints: BoxConstraints.tight(Size(60, 60)),
child: Icon(
Icons.add,
color: Color.fromRGBO(255, 255, 255, 1),
size: 30,
),
shape: CircleBorder(),
fillColor: Color.fromRGBO(46, 54, 143, 1),
padding: EdgeInsets.all(15.0),
elevation: 1,
),
SizedBox(
height: 10,
),
Text(
'Add log',
style: kAddLogLabel,
)
],
),
),
]),
list.isEmpty || chartData.isEmpty
? Expanded(
child: Center(
child: Text("No Log Data.."),
),
)
: Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
height: 150,
alignment: Alignment.center,
child: LineChartWidget(
list: chartData,
isDollar: true,
),
),
SizedBox(
height: 10,
),
MultiSelectChip(
onSelectionChanged: (selectedList) async {
setState(() {
selectedItems = selectedList;
});
await Provider.of<LogProvider>(context, listen: false)
.filterLogList(selectedItems);
},
),
MonthSelect(Color.fromRGBO(246, 246, 246, 1),
onMonthSelectionChanged: (selected) {
setState(() {
selectedMonth = selected;
});
selectedMonth == null
? refreshData(currentMonth)
: refreshData(selectedMonth);
}),
Padding(
padding:
const EdgeInsets.only(top: 10, left: 0, right: 0),
child: Container(
width: double.infinity,
height: 1.0,
color: kDividerColor,
),
),
what i am seeing is the Multiselect Chip has the Same List of Items redrawn/added to the list view 3 times, each time i go into the NewLog screen the list keeps growing
im currently using the same Widget across 4 diffrent screens, but for some reason when i navigate to one of the other screen the list resets and displays the orignal items and the duplicate items dissapear
what can i do to prevent this from redrawing, all the time when navigating off the screen
thanks
Have you tried specifying listen: false in Provider.of() used in didChangeDependencies()? It may solve the issue.
However, there can still be a risk. I doubt initialising something there is safe because didChangeDependencies() is called when/whenever a dependency of the State object changes as written in its document. It'd be safer to do it in initState(), or have it done outside only once and its result passed in to MultiSelectChip.