Class 'Future<dynamic>' has no instance getter 'length' - dart

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.

Related

SliverAppbar remains visible when CustomScrollView with ScrollController is scrolled

Adding a ScrollController to function timelineList() causes the SliverAppBar to remain visible on scroll (when counter list is scrolled, SliverAppBar should hide). The issue goes away if the _scrollController is removed from the list (see timelineList function) but this gives rise to a new problem, I need to listen for when the scrollbar reaches bottom (to get more content).
See sample app below, copy/paste and run.
void main() => runApp(TestApp());
class TestApp extends StatelessWidget {
final _scrollController = new ScrollController();
TestApp(){
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
print('Get more data');
}
});
}
#override
Widget build(BuildContext context) {
TestBloc bloc = TestBloc();
bloc.fetchTestTimeline();
bloc.fetchTestAppBarTxt1();
bloc.fetchTestAppBarTxt2();
return MaterialApp(
home: new Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
backgroundColor: Colors.blueGrey,
elevation: 0.0,
),
body: NestedScrollView(
headerSliverBuilder:
(BuildContext contrxt, bool innerBoxIsScrolled) {
return <Widget>[
buildSliverAppBar(context, bloc),
];
},
body: Column(
children: <Widget>[
timelineList(bloc),
],
)
)),
);
}
buildSliverAppBar(context, TestBloc bloc){
return SliverAppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.grey[400],
expandedHeight: 200.0,
floating: true,
snap: true,
flexibleSpace: FlexibleSpaceBar(
background: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 2.0),
height: 200,
child: Column(
children: <Widget>[
StreamBuilder(
stream: bloc.testAppBarTxt1,
initialData: null,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if (snapshot.data == null)
return buildProgressIndicator(true);
return Expanded(
child: Text('${snapshot.data}'));
}),
StreamBuilder(
stream: bloc.testAppBarTxt2,
initialData: null,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if (snapshot.data == null)
return buildProgressIndicator(true);
return Expanded(
child: Text('${snapshot.data}'));
}),
],
),
)
],
),
));
}
timelineList(TestBloc bloc) {
return StreamBuilder(
stream: bloc.getTestTimeline,
initialData: null,
builder: (BuildContext context, AsyncSnapshot<List<int>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Expanded(child: buildProgressIndicator(true));
}
List<int> val = snapshot.data;
if (val.isNotEmpty) {
addToTimelineList(val, bloc);
return Expanded(
child: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate(new List<Widget>.generate(bloc.listTest.length, (int index) {
if (index == bloc.listTest.length) {
return buildProgressIndicator(bloc.isPerformingRequest);
} else {
return bloc.listTest[index];
}
})
))
],
),
);
}
});
}
void addToTimelineList(List<int> list, TestBloc bloc) {
for (var val in list) {
bloc.listTest.add(Text('$val'));
}
}
}
Widget buildProgressIndicator(showIndicator) {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: showIndicator ? 1.0 : 0.0,
child: Container(
width: 10.0,
height: 10.0,
child: new CircularProgressIndicator(
)),
),
),
);
}
class TestBloc {
String appbar1Val;
String appbar2Val;
List<Text> listTest = new List<Text>();
bool isPerformingRequest = false;
final _testAppBarText1 = BehaviorSubject<String>();
Observable<String> get testAppBarTxt1 => _testAppBarText1.stream;
final _testAppBarText2 = BehaviorSubject<String>();
Observable<String> get testAppBarTxt2 => _testAppBarText2.stream;
final _testTimeline = PublishSubject<List<int>>();
Observable<List<int>> get getTestTimeline => _testTimeline.stream;
fetchTestTimeline() async {
List item = await Future.delayed(
Duration(seconds: 2), () => List<int>.generate(100, (i) => i));
_testTimeline.sink.add(item);
}
fetchTestAppBarTxt1() async {
appbar1Val = await Future.delayed(Duration(seconds: 2), () => "Text One");
_testAppBarText1.sink.add(appbar1Val);
}
fetchTestAppBarTxt2() async {
appbar2Val = await Future.delayed(Duration(seconds: 2), () => "Text Two");
_testAppBarText2.sink.add(appbar2Val);
}
dispose() {
_testAppBarText1.close();
_testAppBarText2.close();
_testTimeline.close();
}
}
It's possible to achive the same result with wrapping your list with a Notification Listener.
NotificationListener<ScrollNotification>(
onNotification: (sn) {
if (sn.metrics.pixels ==
sn.metrics.maxScrollExtent) {
print('Get more data');
}
},
child: CustomScrollView(...
Edit: Since my initial answer didn't cover the animateTo use case, I got it working by removing the outer NestedScrollView. Here is the modified example.
void main() => runApp(TestApp());
class TestApp extends StatelessWidget {
final _scrollController = new ScrollController();
TestApp() {
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
print('Get more data');
}
});
}
#override
Widget build(BuildContext context) {
TestBloc bloc = TestBloc();
bloc.fetchTestTimeline();
bloc.fetchTestAppBarTxt1();
bloc.fetchTestAppBarTxt2();
return MaterialApp(
home: new Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
backgroundColor: Colors.blueGrey,
elevation: 0.0,
),
body: Column(
children: <Widget>[
timelineList(bloc),
],
),
),
);
}
buildSliverAppBar(context, TestBloc bloc) {
return SliverAppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.grey[400],
expandedHeight: 200.0,
floating: true,
snap: true,
flexibleSpace: FlexibleSpaceBar(
background: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 2.0),
height: 200,
child: Column(
children: <Widget>[
StreamBuilder(
stream: bloc.testAppBarTxt1,
initialData: null,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if (snapshot.data == null)
return buildProgressIndicator(true);
return Expanded(child: Text('${snapshot.data}'));
}),
StreamBuilder(
stream: bloc.testAppBarTxt2,
initialData: null,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if (snapshot.data == null)
return buildProgressIndicator(true);
return Expanded(child: Text('${snapshot.data}'));
}),
],
),
)
],
),
));
}
timelineList(TestBloc bloc) {
return StreamBuilder(
stream: bloc.getTestTimeline,
initialData: null,
builder: (BuildContext context, AsyncSnapshot<List<int>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Expanded(child: buildProgressIndicator(true));
}
List<int> val = snapshot.data;
if (val.isNotEmpty) {
addToTimelineList(val, bloc);
return Expanded(
child: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
buildSliverAppBar(context, bloc),
SliverList(
delegate: SliverChildListDelegate(
new List<Widget>.generate(bloc.listTest.length,
(int index) {
if (index == bloc.listTest.length) {
return buildProgressIndicator(bloc.isPerformingRequest);
} else {
return bloc.listTest[index];
}
})))
],
),
);
}
});
}
void addToTimelineList(List<int> list, TestBloc bloc) {
for (var val in list) {
bloc.listTest.add(Text('$val'));
}
}
}
Widget buildProgressIndicator(showIndicator) {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: showIndicator ? 1.0 : 0.0,
child: Container(
width: 10.0, height: 10.0, child: new CircularProgressIndicator()),
),
),
);
}
class TestBloc {
String appbar1Val;
String appbar2Val;
List<Text> listTest = new List<Text>();
bool isPerformingRequest = false;
final _testAppBarText1 = BehaviorSubject<String>();
Observable<String> get testAppBarTxt1 => _testAppBarText1.stream;
final _testAppBarText2 = BehaviorSubject<String>();
Observable<String> get testAppBarTxt2 => _testAppBarText2.stream;
final _testTimeline = PublishSubject<List<int>>();
Observable<List<int>> get getTestTimeline => _testTimeline.stream;
fetchTestTimeline() async {
List item = await Future.delayed(
Duration(seconds: 2), () => List<int>.generate(100, (i) => i));
_testTimeline.sink.add(item);
}
fetchTestAppBarTxt1() async {
appbar1Val = await Future.delayed(Duration(seconds: 2), () => "Text One");
_testAppBarText1.sink.add(appbar1Val);
}
fetchTestAppBarTxt2() async {
appbar2Val = await Future.delayed(Duration(seconds: 2), () => "Text Two");
_testAppBarText2.sink.add(appbar2Val);
}
dispose() {
_testAppBarText1.close();
_testAppBarText2.close();
_testTimeline.close();
}
}

Perform Async Operations from Data gotten from StreamBuilder before displaying

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]))

Flutter Dismissible undo animation using AnimatedList

Code:
Widget build(BuildContext context) {
++flag;
return AnimatedList(
key: Key(flag.toString()),
initialItemCount: numbers.length,
itemBuilder: (context, index, animation) {
return Dismissible(
key: Key(numbers[index].toString()),
background: Container(color: Colors.green),
child: ListTile(title: Text("Item = ${numbers[index].toString()}")),
onDismissed: (direction) {
setState(() => numbers.removeAt(index));
Timer(Duration(milliseconds: 1500), () => setState(() => numbers.insert(index, index)));
},
);
},
);
}
For simplicity I am using Timer to add the deleted number after 1500 ms. Everything works great but I can't see the animation when the list is updated (after 1500 ms), how can I make use of animation parameter to animate the list?
Screenshot:
TL;DR: How can I have animation when the item is put back in the AnimatedList?
List<int> _list = List.generate(5, (i) => i);
GlobalKey<AnimatedListState> _key = GlobalKey();
int _index;
Widget build(BuildContext context) {
return Scaffold(
body: _myWidget(),
appBar: AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.undo),
onPressed: () {
_list.insert(_index, _index);
_key.currentState.insertItem(_index);
},
),
],
),
);
}
Widget _myWidget() {
return AnimatedList(
key: _key,
initialItemCount: _list.length,
itemBuilder: (context, index, animation) {
return Dismissible(
key: Key("${_list[index]}"),
child: SizeTransition(
sizeFactor: animation,
child: ListTile(title: Text("Item = ${_list[index]}")),
),
background: Container(color: Colors.green),
onDismissed: (direction) {
setState(() {
_index = index;
_list.removeAt(index);
_key.currentState.removeItem(index, (_, __) => Container());
});
},
);
},
);
}
To insert items using AnimatedList, you need to call the method AnimatedListState.insertItem(int index)
AnimatedList.of(context).insertItem(0);
You can also obtain the AnimatedListState using a GlobalKey
final foo = GlobalKey<AnimatedListState>();
#override
Widget build(BuildContext context) {
return AnimatedList(
key: foo,
// ...
);
}
// elsewhere
foo.currentState.insertItem(0);

Flutter: Is it Possbile to have Multiple Futurebuilder or A Futurebuilder for Multiple Future Methods?

So let's say I'm fetching different List from Different Url's
so The Future function will look like this
Future<List<City>> getCityDetails(Region selectedRegion) async {}
Future<List<Region>> getregionDetails() async {}
thus the Widget Builder will look like this
FutureBuilder<List<Region>>(
future: getregionDetails(),
builder: (context, snapshot) {}
is there a way or work around in this one? I'm trying to find an answer how to implement this one or is there another way?
i think you are looking for something like this
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget createRegionsListView(BuildContext context, AsyncSnapshot snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: values.length,
itemBuilder: (BuildContext context, int index) {
return values.isNotEmpty
? Column(
children: <Widget>[
ListTile(
title: Text(values[index].region),
),
Divider(
height: 2.0,
),
],
)
: CircularProgressIndicator();
},
);
}
Widget createCountriesListView(BuildContext context, AsyncSnapshot snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: values == null ? 0 : values.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedCountry = values[index].code;
});
print(values[index].code);
print(selectedCountry);
},
child: Column(
children: <Widget>[
new ListTile(
title: Text(values[index].name),
selected: values[index].code == selectedCountry,
),
Divider(
height: 2.0,
),
],
),
);
},
);
}
final String API_KEY = "03f6c3123ea549f334f2f67c61980983";
Future<List<Country>> getCountries() async {
final response = await http
.get('http://battuta.medunes.net/api/country/all/?key=$API_KEY');
if (response.statusCode == 200) {
var parsedCountryList = json.decode(response.body);
List<Country> countries = List<Country>();
parsedCountryList.forEach((country) {
countries.add(Country.fromJSON(country));
});
return countries;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load ');
}
}
Future<List<Region>> getRegions(String sl) async {
final response = await http
.get('http://battuta.medunes.net/api/region/$sl/all/?key=$API_KEY');
if (response.statusCode == 200) {
var parsedCountryList = json.decode(response.body);
List<Region> regions = List<Region>();
parsedCountryList.forEach((region) {
regions.add(Region.fromJSON(region));
});
return regions;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load ');
}
}
String selectedCountry = "AF";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Row(children: [
Expanded(
child: FutureBuilder(
future: getCountries(),
initialData: [],
builder: (context, snapshot) {
return createCountriesListView(context, snapshot);
}),
),
Expanded(
child: FutureBuilder(
future: getRegions(selectedCountry),
initialData: [],
builder: (context, snapshot) {
return createRegionsListView(context, snapshot);
}),
),
]),
);
}
}
class Country {
String name;
String code;
Country({this.name, this.code});
factory Country.fromJSON(Map<String, dynamic> json) {
return Country(
name: json['name'],
code: json['code'],
);
}
}
class Region {
String country;
String region;
Region({this.country, this.region});
factory Region.fromJSON(Map<String, dynamic> json) {
return Region(
region: json["region"],
country: json["country"],
);
}
}

how to get a list of files from the directory and pass it to the ListView?

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());
}),
)
],
),
),
),
);
}

Resources