How do i implement a scrollable futurebuilder?
I have this snippet. but rather than make it scroll up, it just does not scroll at all.
The snippet looks like this :
Center(
child: FutureBuilder<List<TransactionDetails>>(
future: fetchAlbum(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Image.network(
snapshot.data![index].avatar.toString()),
),
title:
Text(snapshot.data![index].name.toString()),
trailing: Text(
snapshot.data![index].amount.toString()),
subtitle: Text(
snapshot.data![index].date.toString(),
style: TextStyle(fontSize: 9),
),
);
});
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
}))
How do I get it to do something like that scroll? Please I need some help here.
I assume you have enough data to scroll the view. in case you don't have enough data to scroll and want the scroll UX. i'll suggest you add the scroll physics to list view.
ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
)
You can try wrapping the FutureBuilder() with a Column() because of your ListView.builder and then wrap the Column with a SingleChildScrollView(). The Column widget always tries to expand as big as it can, so you wrap it with a SingleChildScrollView to make it scrollable. The ListView.builder is already a scrollable by it self, but since you need to scroll the whole FutureBuilder you can do it this way. If you want to disable the list view inside the ListView.builder, you can use physics: NeverScrollableScrollPhysics().
SingleChildScrollView(
child: Column(children:[
Center(
child: FutureBuilder<List<TransactionDetails>>(
future: fetchAlbum(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Image.network(
snapshot.data![index].avatar.toString()),
),
title:
Text(snapshot.data![index].name.toString()),
trailing: Text(
snapshot.data![index].amount.toString()),
subtitle: Text(
snapshot.data![index].date.toString(),
style: TextStyle(fontSize: 9),
),
);
});
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
}))
]),
),
Related
This is the code where the error occurred using GetX. If anyone want to help thanks for advance
body: SafeArea(
child: Column(
children: [
Expanded(
child: GetX<CustomerController> (
builder: (customerController) {
return ListView.builder(
itemCount: customerController.count,
itemBuilder: (context, index) {
return ListTile(
selectedTileColor:Colors.blueGrey.shade50,
title: Text(customerController.results.string),
);
});
},
),
)
],
),
),
Create a GetX Controller and then assign it to your GetX Widget
GetX<ControllerName>(
builder: (customerController) {
return ListView.builder(
itemCount: customerController.controllervalueinobx.length, //should be obx/Rx type variable
itemBuilder: (context, index) {
return ListTile(
selectedTileColor: Colors.blueGrey.shade50,
title: Text(
"customerController.results.string",
), );
});
},
),
I am using an API to build a movies application, I had a problem with making theListView to be from left to right instead of up and dowm.I am trying to create a horizontal list view but it displayed not as expected. You can see how it looks in the Image bellow. It works with me usually but it my first time to do that inside a listview builder. How to fix that?
Note: I want the full screen to be vertical and this part only horizontal.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child:
FutureBuilder(
future: getData(),
builder: (BuildContext context,AsyncSnapshot snapshot){
if(snapshot.data == null){
return Container(
child: Center(
child:CircularProgressIndicator() ,),);
}
else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context,int i){
if(snapshot.data==null){
return Center(
child: CircularProgressIndicator(),
);
}
else{
return Container(
height: 250,
child: Card(
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Image(image: NetworkImage(snapshot.data[i].poster))
],
),
),
);
}}
);
}
}
,),
),
);
}
}
Image
You can use scrollDirection: Axis.horizontal,
inside the Listview.Builder to make it scroll horizontally and add a width for the container that's being returned.
Try below code hope its helpful to you . declare your ListView.builder() like below refer Listview here
Container(
width: double.infinity,
height: 180,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 10,
itemBuilder: (BuildContext context, int i) {
return Container(
height: 50,
child: Card(
child: Image.network(
'https://tech.pelmorex.com/wp-content/uploads/2020/10/flutter.png',
),
),
);
},
),
),
Your result screen->
I have a RefreshIndicator contained within a StreamBuilder. Anytime the Streambuilder has new data added, the RefreshIndicator rebuilds its Listview.Builder jumping to the top in the process.
StreamBuilder(
stream: apiResultStream.stream,
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasError){
print("has error");
}
if(!snapshot.hasData)
{
return RefreshIndicator(
onRefresh: () {
_apiResult=[];
return _loadMoreData(0);
},
child:snapshot.data.length == 0 ? Padding(
padding: const EdgeInsets.all(20.0),
child: Center(child: Text('No items', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),)),
):SingleChildScrollView(
controller: scrollController,
physics: const AlwaysScrollableScrollPhysics(),
child:ListView.builder(
itemBuilder:(BuildContext ctxt, int index){
return InkWell(
child:TripItem(key: ValueKey(snapshot.data[index].Id),item:snapshot.data[index])
);
}
,itemCount:snapshot.data.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
key: UniqueKey(),
))
);
The Solution is to add a GlobalKey to the RefreshIndicator. This prevents the RefreshIndicator from rebuilding its child when the StreamBuilder has new data.
StreamBuilder(
stream: apiResultStream.stream,
builder:
(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if(snapshot.hasError){
print("has error");
}
if(!snapshot.hasData)
{
return RefreshIndicator(
key: _refreshIndicatorKey ,
onRefresh: () {
_apiResult=[];
return _loadMoreData(0);
},
child:snapshot.data.length == 0 ? Padding(
padding: const EdgeInsets.all(20.0),
child: Center(child: Text('No items', style:
TextStyle(fontSize: 16.0, fontWeight:
FontWeight.bold),)),
):SingleChildScrollView(
controller: scrollController,
physics: const AlwaysScrollableScrollPhysics(),
child:ListView.builder(
itemBuilder:(BuildContext ctxt, int index){
return InkWell(
child:TripItem(key:
ValueKey(snapshot.data[index].Id),item:snapshot.data[index])
);
}
,itemCount:snapshot.data.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
key: UniqueKey(),
))
);
I want to create a ToDo-App that saves the ToDo's in Firestore.
I am already able to add every new ToDo Item to Firestore and now I want those Items that were added to pop up when the application opens.
I have made the following:
body: Column(
children:<Widget>[
StreamBuilder<QuerySnapshot>(
stream:FirebaseFirestore.instance.collection("TO-DO-Collection").snapshots(),
builder: (context,snapshot){
if(!snapshot.hasData) return LinearProgressIndicator();
return Expanded(
child: _buildList(snapshot.requireData),
);
},
),
Expanded(
child:ListView(
children: _getItems(),
),
),
],
),
Here the method to build the List with all the stored ToDo's:
Widget _buildList(QuerySnapshot snapshot){
return ListView.builder(
itemCount: snapshot.docs.length,
itemBuilder: (context,index){
final doc=snapshot.docs[index];
return _buildTodoItem(doc["task"]);
},
);
}
(The function _buildTodoItem simply returns a List Tile)
This creates two ListViews (one of the first half of the screen and the other one on the other). Is there any possible way to unify both?
Wrap your column with SingleChildScrollView and put physics: NeverScrollableScrollPhysics(). This will merge the scroll of both of your lists.
body: SingleChildScrollView(
child :Column(
children:<Widget>[
StreamBuilder<QuerySnapshot>(
stream:FirebaseFirestore.instance.collection("TO-DO-Collection").snapshots(),
builder: (context,snapshot){
if(!snapshot.hasData) return LinearProgressIndicator();
return _buildList(snapshot.requireData);
},
),
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: _getItems(),
),
],
),),
Widget _buildList(QuerySnapshot snapshot) {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: snapshot.docs.length,
itemBuilder: (context, index) {
final doc = snapshot.docs[index];
return _buildTodoItem(doc["task"]);
},
);
}
I have widget which return CircularProgressIndicator()
it shows on the circular mark upper left of screen.
However I want to put this as overlay and put at the center of screen.
I am checking widget list but I cant find what Widget should I use as overlay.
On which layer should I put this on??
For now my code is like this ,when loading it shows CircularProgressIndicator instead of ListView
However I want to put CircularProgressIndicator() on ListView
Widget build(BuildContext context) {
if(loading) {
return CircularProgressIndicator();
}
return ListView.builder(
controller: _controller,
itemCount: articles.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(articles[index]),
);
},
);
}
Thank you very much for answers.
I solve with stack Widget like this below.
At first I try to use overlay, but I bumped into some errors.
So, I use simply stack.
#override
Widget build(BuildContext context) {
Widget tempWidget = new CircularProgressIndicator();
if(loading) {
tempWidget = new CircularProgressIndicator();
}
else {
tempWidget = new Center();//EmptyWidget
}
return Stack(
children: <Widget>[
ListView.builder(
controller: _controller,
itemCount: articles.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(articles[index].title),
onTap: () => onTapped(context,articles[index].url),
);
},
),
Center(
child: tempWidget
),
]
);
}
Stack(
children: <Widget>[
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100,
color: Colors.red,
);
},
itemCount: 10,
),
Center(
child: CircularProgressIndicator(),
),
],
)
Stack(
children: <Widget>[
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100,
color: Colors.red,
);
},
itemCount: 10,
),
isLoading? Container(child: Center(
child: CircularProgressIndicator(),
)): Container(), //if isLoading flag is true it'll display the progress indicator
],
)
or you can use futureBuilder or streamBuilder when loading data from somewhere and you want to change the ui depending on the state
To overlay or position items on top of each other you would usually use a Stack widget or Overlay as described here. For your usecase I would recommend checking out the modal progress hud package.