I am currently using StreamBuilder to get data from Firestore and so far, it is working good.
I currently want to perform some async operations to the data before displaying.
The code to get the data is below.
List<Model> listToDisplay = new List<Model>();
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: topBar,
body: StreamBuilder(
stream: Firestore.instance.collection('/myPath').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.connectionState == ConnectionState.active) {
listToDisplay.clear();
for (DocumentSnapshot _snap in snapshot.data.documents) {
Model _add = new Model.from(_snap);
listToDisplay.add(_add);
}
return TabBarView(
children: <Widget>[
ListView.builder(
itemCount: mouveList.length,
itemBuilder: (context, index) {
return Card(listToDisplay[index]);
},
),
Icon(Icons.directions_transit),
],
);
} else {
return Container(
child: Center(child: CircularProgressIndicator()));
}
})));
I tried adding the async operation in the for in loop but that did not work, it did not wait for it. Also, add await did not work because Widget build(BuildContext context) cannot be async.
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: topBar,
body: StreamBuilder(
stream: Firestore.instance.collection('/myPath').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.connectionState == ConnectionState.active) {
listToDisplay.clear();
for (DocumentSnapshot _snap in snapshot.data.documents) {
Model _add = new Model.from(_snap);
//Added
//_add.getCalculate(); <------- Async function
_add.Calculate(); <------ Flutter does not wait for this
await _add.Calculate(); <------ Produces an error
listToDisplay.add(_add);
}
return TabBarView(
children: <Widget>[
ListView.builder(
itemCount: mouveList.length,
itemBuilder: (context, index) {
return Card(listToDisplay[index]);
},
),
Icon(Icons.directions_transit),
],
);
} else {
return Container(
child: Center(child: CircularProgressIndicator()));
}
})));
Any ideas on how to get data as stream, perform operations on the data before displaying the data all using StreamBuilder and ListViewBuilder ?
I'm currently iterating the data from a StreamBuilder in corresponding lists and then using a ListView.builder to display each data item from List.count. The code begins with these public/file Lists...
List names = new List();
List ids = new List();
List vidImages = new List();
List numbers = new List();
Then this in my Stateful Widget Builder...
child: new StreamBuilder(
stream:
fb.child('child').orderByChild('value').onValue,
builder:
(BuildContext context, AsyncSnapshot<Event> event) {
if (event.data?.snapshot?.value == null) {
return new Card(
child: new Text(
'Network Error, Please Try again...',
style: new TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic)),
);
} else if (event.data?.snapshot?.value != null) {
Map myMap =
event.data?.snapshot?.value; //store each map
var titles = myMap.values;
List onesTitles = new List();
List onesIds = new List();
List onesImages = new List();
List onesRank = new List();
List<Top> videos = new List();
for (var items in titles) {
var top = new Top(
videoId: items['vidId'],
rank: items['Value'],
title: items['vidTitle'],
imageString: items['vidImage']);
videos.add(top);
videos..sort((a, b) => b.rank.compareTo(a.rank));
}
for (var vids in videos) {
onesTitles.add(vids.title);
onesIds.add(vids.videoId);
onesImages.add(vids.imageString);
onesRank.add(vids.rank);
}
names = onesTitles;
ids = onesIds;
numbers = onesRank;
vidImages = onesImages;
switch (event.connectionState) {
case ConnectionState.waiting:
return new Card(
child: new Text('Loading...',
style: new TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic)),
);
else
return new InkWell( child: new ListView.builder(
itemCount:
names == null ? 0 : names.length,
itemBuilder:
(BuildContext context, int index) {
return new Card( child: new Text(names[index]))
Related
Im trying to get LayoutBuilder working with some items from my API.
with this code :
class _ContactsScreenState extends State<ContactsScreen> {
final _contacts = _dummyData();
final _selection = ValueNotifier<ResumenPublicaciones>(null);
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
var futureBuilder = new FutureBuilder(
future: _dummyData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else
return buildLayoutBuilder();
}
},
);
return new Scaffold(
body: futureBuilder,
);
}
LayoutBuilder buildLayoutBuilder() {
return LayoutBuilder(builder: (context, dimens) {
if (dimens.maxWidth >= kTabletBreakpoint) {
const kListViewWidth = 300.0;
return Row(
children: <Widget>[
Container(
width: kListViewWidth,
child: buildListView((val) {
_selection.value = val;
}),
),
VerticalDivider(width: 0),
Expanded(
child: ValueListenableBuilder<ResumenPublicaciones>(
valueListenable: _selection,
builder: (context, contact, child) {
if (contact == null) {
return Scaffold(
appBar: AppBar(),
body: Center(child: Text('No Contact Selected')),
);
}
return ContactDetails(contact: contact);
},
))
],
);
}
return buildListView((val) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ContactDetails(contact: val),
),
);
});
});
}
Widget buildListView(ValueChanged<ResumenPublicaciones> onSelect) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text('Contacts'),
),
body: ListView.separated(
separatorBuilder: (context, index) => Divider(height: 0),
itemCount: _contacts.length,
itemBuilder: (context, index) {
final _contact = _contacts[index];
return ListTile(
leading: Icon(Icons.person),
title: Text(_contact.name),
subtitle: Text(_contact.count),
onTap: () => onSelect(_contact),
);
},
),
);
}
}
_dummyData() async {
var res = await fetchJobs(http.Client());
return res;
}
Im receiving this error : Class 'Future' has no instance getter 'length'.
Any Idea on how could I do this? Ias per what I read, I would need to do somethin like var _contact = Await dummyData(). But im not sure where should where.
You can't await in field initializers or in constructors. Your best choice is to keep the type of _contacts as Future<Object>, and then await it where you use the value:
itemCount: (await _contacts).length
That makes your build method asynchronous, which I believe is an issue for Flutter. You may need to use a FutureBuilder.
I tried to get data from firebase but the function didn't work when i initialize it in initState.
and i tried to give it debugprint, it doesn't show in the terminal and there is no error or warning when i run the app.
void _getMarker() {
StreamBuilder(
stream: Firestore.instance
.collection('contentislamis')
.where('kategori', isEqualTo: 'Landmark')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.green)));
} else {
for (int i = 0; i < snapshot.data.documents.length; i++) {
_addMarkers(snapshot.data.documents[i]);
print("${snapshot.data.documents.length} markers added");
}
}
});
}
and this is the function to show the marker
void _addMarkers(DocumentSnapshot markData) {
final String markerIdVal = markData.documentID.toString();
final MarkerId markerId = MarkerId(markerIdVal);
double lat = double.tryParse(markData['posLat'].toString());
double long = double.tryParse(markData['posLong'].toString());
final Marker marker = Marker(
markerId: markerId,
position: LatLng(
lat,
long,
),
infoWindow: InfoWindow(
title: markData['judul'].toString(),
snippet: markData['posLat'] + markData['posLong']
),
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRed)
);
setState(() {
markers[markerId] = marker;
});
}
You need to add the key of the data you want to get from firestore
for eg:
// title is the key in the firestore documents, you need to add your key here
addMarkers(snapshot.data.documents[i].data["title"])
Following code should help you, in this example i am getting the data from cloud firestore and displaying it in Listview :
Code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("posts").snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return new Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text("Loading..."),
SizedBox(
height: 50.0,
),
CircularProgressIndicator()
],
),
);
} else {
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (_, index) {
return Card(
child: ListTile(
title: Text(
snapshot.data.documents[index].data["title"]), // getting the data from firestore
),
);
},
);
}
},
),
),
);
}
future builder running multiple times and page opening multiple at the same time. How to fix this error?
SubCategory StatefulWidget
class subCategory extends StatefulWidget {
final int RegId;
final int AssetId;
final String title;
final int ParentId;
final int equipmentId;
subCategory(this.RegId, this.AssetId, this.title, this.ParentId,this.equipmentId, {Key key})
: super(key: key);
#override
State<StatefulWidget> createState() => _mainCategory();
}
_mainCategory State Widget
class _mainCategory extends State<subCategory> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: submitRequestAppBar(context),
body: Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey[350],
leading: Container(),
title: Text(
widget.title,
textAlign: TextAlign.left,
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),),),
FutureBuilder inside Body
body: FutureBuilder(
future: getRegister1(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return waitingCircle();
case ConnectionState.done:
if (snapshot.hasError) return Text('Error: ${snapshot.error}');
if (snapshot.data.length == 0)
return noResultFound();
else
return createListView(context, snapshot); }
return null; // unreachable
},)),); }
CreateListView Widget
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
List<SubCategoryItem> values = snapshot.data;
return ListView
return ListView.builder(
padding: EdgeInsets.only(top: 8.0, right: 0.0, left: 0.0),
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return GridView.count(
physics: ScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 4,
children: List.generate(values.length, (index) {
return GridTile
return GridTile(
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WoDescription2(
widget.RegId,
widget.AssetId,
widget.ParentId,
values[index].childId,
false,
1,
widget.title,
widget.equipmentId))),
Column Widget
child: Column(
children: [
Card(
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.blueAccent, width: 1.5)),
child: Stack(
children: <Widget>[
flutter_svg plugin use for svg images
SvgPicture.asset('assets/images/Defect/icon-${values[index].childId}.svg',
height: 50.0,),],),), ),
Expanded(
child: Text(
'${values[index].description}',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 10.0),),),],),), ); }),); },);}
FutureBuider future:getRegister1
Future getRegister1() async {
List<SubCategoryItem> description = [];
List cat = [];
var catLocal = (await HelperDatabase1().displayDefCatRelation());
var defCatLocal = (await HelperDatabase1().display());
for (int i = 0; i < catLocal.length; i++) {
if (widget.RegId == catLocal[i].r &&
widget.AssetId == catLocal[i].t &&
widget.ParentId == catLocal[i].p) {
cat.add(catLocal[i].c);}}
for (int i = 0; i < cat.length; i++) {
for (int j = 0; j < defCatLocal.length; j++) {
if (cat[i] == defCatLocal[j].deF_CAT_ID) {
var oneItem = SubCategoryItem(
childId: defCatLocal[j].deF_CAT_ID,
description: defCatLocal[j].description);
await description.add(oneItem);}}}
return description;}}
SubCategoryItem class
class SubCategoryItem {
int childId;String description;
SubCategoryItem({this.childId, this.description});}
Just declare the Future out de Build method / on the initState
_mainCategory State Widget
class _mainCategory extends State<subCategory> {
Future _futureData;
#override
void initState() {
super.initState();
_futureData = getRegister1();
}
#override
Widget build(BuildContext context) {
return Scaffold(
FutureBuilder inside Body
body: FutureBuilder(
future: _futureData,
builder: (BuildContext context, AsyncSnapshot snapshot) {
I get the list of files from the user's folder. The names of the files I transfer to the ListView.builder. It's work, but I think, this is bad architecture.
A method _getFilesFromDir() call with a high frequency.
How to make the correct list generation, so as not to update the interface without changing the file list?
class CharacteristList extends StatefulWidget {
#override
_CharacteristListState createState() => new _CharacteristListState();
}
class _CharacteristListState extends State<CharacteristList> {
List<String> filesList = new List<String>();
List<String> filesL = new List<String>();
#override
void initState() {
super.initState();
filesList = [];
}
Future<List<String>> _getFilesFromDir() async{
filesL = await FilesInDirectory().getFilesFromDir();
setState(() {
filesList = filesL;
});
return filesList;
}
_getFilesCount(){
_getFilesFromDir();
int count = filesList.length;
return count;
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text('Список документов'),
),
body: new Column(
children: <Widget>[
new Expanded(
child: new ListView.builder(
//TODO не успевает сформировать список файлов
itemCount: _getFilesCount(),
itemBuilder: (context, index){
return new CharacteristListItem(filesList[index]);
},
),
),
],
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
Navigator.push(context,
new MaterialPageRoute(builder: (context)
=> new StartScreen()),
);},
child: new Icon(Icons.add),
),
);
}
}
// add dependancy in pubspec.yaml
path_provider:
import 'dart:io' as io;
import 'package:path_provider/path_provider.dart';
//Declare Globaly
String directory;
List file = new List();
#override
void initState() {
// TODO: implement initState
super.initState();
_listofFiles();
}
// Make New Function
void _listofFiles() async {
directory = (await getApplicationDocumentsDirectory()).path;
setState(() {
file = io.Directory("$directory/resume/").listSync(); //use your folder name insted of resume.
});
}
// Build Part
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
title: 'List of Files',
home: Scaffold(
appBar: AppBar(
title: Text("Get List of Files with whole Path"),
),
body: Container(
child: Column(
children: <Widget>[
// your Content if there
Expanded(
child: ListView.builder(
itemCount: file.length,
itemBuilder: (BuildContext context, int index) {
return Text(file[index].toString());
}),
)
],
),
),
),
);
}
Don't call _getFilesCount() in build(). build() can be called very frequently. Call it in initState() and store the result instead of re-reading over and over again.
I changed the architecture of the class - I used FutureBuilder.
class _CharacteristListState extends State<CharacteristList> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text('Список документов'),
),
body: new Center(
child: new Column(
children: <Widget>[
new FutureBuilder(
future: _inFutureList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.connectionState == ConnectionState.waiting){
return new Text('Data is loading...');
}
else{
return customBuild(context, snapshot);
}
}
)
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
Navigator.push(context,
new MaterialPageRoute(builder: (context)
=> new StartScreen()),
);},
child: new Icon(Icons.add),
),
);
}
Widget customBuild(BuildContext context, AsyncSnapshot snapshot){
List<String> values = snapshot.data;
return new Container(
child: new Expanded(
child: new ListView.builder(
itemCount: values.length,
itemBuilder: (context, index){
return new CharacteristListItem(values[index]);
},
),
)
);
}
Future<List<String>>_inFutureList() async{
var filesList = new List<String>();
filesList = await FilesInDirectory().getFilesFromDir();
await new Future.delayed(new Duration(milliseconds: 500));
return filesList;
}
}
// add dependancy in pubspec.yaml
path_provider:
import 'dart:io' as io;
import 'package:path_provider/path_provider.dart';
//Declare Globaly
String directory;
List file = new List();
#override
void initState() {
// TODO: implement initState
super.initState();
_listofFiles();
}
// Make New Function
void _listofFiles() async {
directory = "/storage/emulated/0/Android/data/"; //Give your folder path
setState(() {
file = io.Directory("$directory/resume/").listSync(); //use your folder name insted of resume.
});
}
// Build Part
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
title: 'List of Files',
home: Scaffold(
appBar: AppBar(
title: Text("Get List of Files with whole Path"),
),
body: Container(
child: Column(
children: <Widget>[
// your Content if there
Expanded(
child: ListView.builder(
itemCount: file.length,
itemBuilder: (BuildContext context, int index) {
return Text(file[index].toString());
}),
)
],
),
),
),
);
}
I have a FutureBuilder that gets DISTINCT dates from a local sqlite DB, then I take each date and get the messages for those dates to put them in the widget, this works fine, until you want to listen realtime to a stream or poll for new messages which rebuilds the widgets and flickers the page and then scrolls to the beginning each time. I am hoping to find a way to take all the data into some object or other widget and then group by date and order, etc.. This way I can listen to a stream for updated messages, etc..
Any help would be great, here is my code if it helps anyone see what I do, this is after I converted to Streambuilder, but same result.
new StreamBuilder(
initialData: myInitialData,
stream: msgstream,
builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Waiting to start');
case ConnectionState.waiting:
return new Text('');
default:
if (snapshot.hasError) {
return new Text('Error: ${snapshot.error}');
} else {
myInitialData = snapshot.data;
return new RefreshIndicator(
child: new ListView.builder(
itemBuilder: (context, index) {
return new MyChatWidget(
datediv: snapshot.data[index]['msgdate'],
msgkey: snapshot.data[index]['msgkey'],
);
},
//itemBuilder: _itemBuilder,
controller: _scrollController,
reverse: true,
itemCount: snapshot.data.length,
),
onRefresh: _onRefresh
);
}
}
}),
This is the Widget that the StreamBuilder calls:
class MyChatWidget extends StatefulWidget {
MyChatWidget({Key key, this.datediv, this.msgkey}) : super(key: key);
final String datediv;
final String msgkey;
#override
_MyChatWidgetState createState() => new _MyChatWidgetState();
}
class _MyChatWidgetState extends State<MyChatWidget> {
List<Widget> messagelist;
int messagecount = 0;
var jsonCodec = const JsonCodec();
var mydate = '';
var _urlMessages = '';
PageStorageKey _key;
VideoPlayerController vcontroller;
//Future<http.Response> _responseFuture;
Future<List<Map>> _responseFuture;
List messList;
var mybytes;
File myimageview;
Image newimageview;
String imgStr;
String vidStr;
String vidimgstr;
bool submitting = false;
List<Map> myInitialData;
Stream<List<Map>> msgstream;
#override
void initState() {
super.initState();
if (new DateFormat.yMd().format(DateTime.parse(widget.datediv)) ==
new DateFormat.yMd().format(new DateTime.now())) {
mydate = 'Today';
} else {
mydate = new DateFormat.yMMMEd().format(DateTime.parse(widget.datediv));
}
DateChatMessage dcm =
new DateChatMessage(widget.msgkey, widget.datediv.toString());
var json = jsonCodec.encode(dcm);
_urlMessages =
'http://loop-dev.clinicalsoftworks.com/chat/messages/getbydate';
//_responseFuture = http.post(_urlMessages, body: json, headers: getAuthHeader());
_responseFuture =
ChatDB.instance.getMessagesByDate(widget.msgkey, widget.datediv);
msgstream = new Stream.fromFuture(_responseFuture);
//controller = new TabController(length: 4, vsync: this);
//_getMessages();
}
/*#override
void dispose() {
super.dispose();
if (vcontroller != null) {
vcontroller.dispose();
}
}*/
#override
Widget build(BuildContext context) {
_key = new PageStorageKey('${widget.datediv.toString()}');
return new Column(
children: <Widget>[
new Container(
child: new Text(
mydate,
textAlign: TextAlign.left,
style: new TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
alignment: Alignment.centerLeft,
padding: new EdgeInsets.only(left: 10.0),
),
new Container(
child: new Divider(
height: 5.0,
color: Colors.grey,
),
padding: new EdgeInsets.only(left: 10.0, right: 10.0),
),
/**/
new StreamBuilder(
initialData: myInitialData,
stream: msgstream,
builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Waiting to start');
case ConnectionState.waiting:
return new Text('');
default:
myInitialData = snapshot.data;
List<dynamic> json = snapshot.data;
messagelist = [];
json.forEach((element) {
DateTime submitdate =
DateTime.parse(element['submitdate']).toLocal();
String myvideo = (element['chatvideo']);
String myimage = element['chatimage'];
String myvideoimage = element['chatvideoimage'];
File imgfile;
File vidfile;
File vidimgfile;
bool vidInit = false;
Future<Null> _launched;
String localAssetPath;
String localVideoPath;
String mymessage = element['message'].replaceAll("[\u2018\u2019]", "'");
//print('MYDATE: '+submitdate.toString());
_checkFile(File file) async {
var checkfile = await file.exists();
print('VIDEXISTS: '+checkfile.toString());
}
Future<Null> _launchVideo(String url, bool isLocal) async {
if (await canLaunchVideo(url, isLocal)) {
await launchVideo(url, isLocal);
} else {
throw 'Could not launch $url';
}
}
void _launchLocal() =>
setState(() => _launched = _launchVideo(localVideoPath, true)
);
Widget _showVideo() {
/*return new Flexible(
child: new vplayer.VideoCard(
controller: vcontroller,
title: element['referralname'],
subtitle: 'video',
),
);*/
return new Flexible(
child: new Card(
child: new Column(
children: <Widget>[
new ListTile(subtitle: new Text('Video'), title: new Text(element['referralname']),),
new GestureDetector(
onTap: _launchLocal,
child: new Image.file(
vidimgfile,
width: 150.0,
),
),
],
),
)
);
}
_initVideo() {
setState(() {vidInit = true;});
}
_onError() {
print('VIDEO INIT ERROR');
}
if (myimage != "") {
imgStr = element['chatimage'];
imgfile = new File(imgStr);
}
if (myvideo != "") {
vidStr = element['chatvideo'];
vidimgstr = element['chatvideoimage'];
vidimgfile = new File(vidimgstr);
//vidfile = new File(vidStr);
//_checkFile(vidfile);
//print('vidfile: '+vidfile.path);
localVideoPath = '$vidStr';
//print('LOCALVIDEO: '+localVideoPath);
//vcontroller = new VideoPlayerController('file://$vidStr')..initialize();
}
_showLgPic() {
Route route = new MaterialPageRoute(
settings: new RouteSettings(name: "/ShowPic"),
builder: (BuildContext context) => new ShowPic(
image: imgfile,
),
);
Navigator.of(context).push(route);
}
Widget _showGraphic() {
Widget mywidget;
if (myimage != "") {
mywidget = new GestureDetector(
child: new Image.file(
imgfile,
width: 300.0,
),
onTap: _showLgPic,
);
} else if (myvideo != "") {
mywidget = _showVideo();
} else {
mywidget = new Container();
}
return mywidget;
}
messagelist.add(
new Container(
//width: 300.0,
padding: new EdgeInsets.all(10.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Container(
padding: new EdgeInsets.only(bottom: 5.0),
child: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new CircleAvatar(
child: new Text(
element['sendname'][0],
style: new TextStyle(fontSize: 15.0),
),
radius: 12.0,
),
new Text(' '),
new Text(
element['sendname'],
style: new TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold),
),
new Text(' '),
new Text(
new DateFormat.Hm().format(submitdate),
style: new TextStyle(
color: Colors.grey, fontSize: 12.0),
),
],
),
),
new Row(
children: <Widget>[
new Text(' '),
new Flexible(
child: new Text(mymessage),
)
],
),
new Container(
width: 150.0,
child: new Row(
children: <Widget>[
new Text(' '),
_showGraphic()
/*myimage != ""
? new GestureDetector(
child: new Image.file(
imgfile,
width: 300.0,
),
onTap: _showLgPic,
)
: myvideo != "" ? _showVideo() : new Container(),*/
],
)),
],
),
),
);
});
return new Column(children: messagelist);
}
},
)
],
);
}
}
Thanks for any assistance
which rebuilds the widgets and flickers the page and then scrolls to the beginning each time
To solve problem with scrolling try ScrollController. Create your own, keep it between updates and inject into List you created.
To solve flickering you could use Key for List widgets. Key should be unique identifier of message, e.g. msgkey
This example how to keep scrolloffset works for me
class SomeWidget extends StatefulWidget {
#override
_SomeWidgetState createState() => new _SomeWidgetState();
}
class _SomeWidgetState extends State<SomeWidget> {
ScrollController _scrollController;
int _count;
#override
void initState() {
super.initState();
_count = 10;
_scrollController = new ScrollController();
}
void _add() {
setState(() => _count += 5);
}
#override
Widget build(BuildContext context) {
final _titles = new List<String>.generate(_count, (i) => 'Title ${i}');
return new Scaffold(
appBar: new AppBar(
title: new Text("Demo"),
actions: <Widget>[
new IconButton(icon: new Icon(Icons.add), onPressed: _add)
],
),
body: new ListView.builder(
controller: _scrollController,
itemCount: _titles.length,
itemBuilder: (context, index) => new ListTile(
title: new Text(_titles[index]),
),
),
);
}
}