FutureBuilder rebuilds because of TextField in Flutter - flutter

The problem is when I try to input some text into textfield, the keyboard shows up for a second, and then the whole FutureBuilder rebuilds immediately.
Here is my FutureBuilder
body: FutureBuilder(
future: Provider.of<Activities>(context, listen: false).fetchAndSet(),
builder: (context, snapshot) => snapshot.connectionState ==
ConnectionState.waiting
? Center(child: CircularProgressIndicator())
: Consumer<Activities>(
child: Center(
child: const Text('nothing here'),
),
builder: (context, activities, ch) => SingleChildScrollView(
child: Center(
child: Column(children: [
Container(
padding:
EdgeInsets.only(top: mediaQuery.size.height / 40),
child: Text(time, style: TextStyle(fontSize: 30)),
),
DayContainer(mediaQuery, activities),
Container(
height: 300,
child: SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
children: <Widget>[
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: activities.activities.length,
itemBuilder: (context, index) {
return ElementPicker(
mediaQuery,
// this.callbackN,
activities.activities[index]);
})
],
),
),
),
FloatingActionButton(
onPressed: () => activities.addActivity(
'0Adding0', 'Добавить активность', 0.0, 0.0),
child: Icon(Icons.add),
)
]),
),
),
),
)
Inside of ElementPicker, there is another widget in which there is TextField

You need to initialize your futures in the initState so that whenever the widget rebuilds for any reason (in this case opening of the keyboard), you don't perform the fetchAndSet again:
void initState() {
super.initState();
fetchAndSetFuture = Provider.of<Activities>(context, listen: false).fetchAndSet();
}
...
//in build()
FutureBuilder(
future: fetchAndSetFuture,
builder: ...
);

Related

Grid view.builder ontap functionality not working

I tried putting inkwell and also gesture detector widgets but onTap() doesn't seem to work in any scenario.
I am dynamically adding data to gridView using futureBuilder and I am adding on tap functionality using InkWell and also tried GestureDetector but it seems gridView does not accept any taps!
FutureBuilder(
future: getAllFriends(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
padding: const EdgeInsets.all(8),
height: MediaQuery.of(context).size.height,
decoration: const BoxDecoration(color: Color(0xFFDBE2E7)),
child: GridView.builder(
padding: EdgeInsets.zero,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 0.8,
),
itemCount: friendsList.length,
itemBuilder: (context, index) {
return InkWell(
onTap: () {
print('object');
},
child: Container(
color: Colors.amber.shade100,
child: friendCircle(
friendsList[index].friendPoint,
friendsList[index].friendPic,
friendsList[index].friendName,
),
),
);
},
),
);
} else {
return const SizedBox(
width: 300,
height: 300,
child: IgnorePointer(
child: Center(
child: CircularProgressIndicator(),
),
));
}
}),

How to make ListView Scrollable in flutter

Newbie here. I have managed to implement a ListView that simply displays images. However the ListView isn't scrollable. I have attempted to wrap it in SingleChildScrollView, have added physics to AlwaysScrollableScrollPhysics and also tried removing Expand widgets from the layout. What am I missing?
LAYOUT
return Scaffold(
body: SingleChildScrollView(
child: Column(children: [
SizedBox(
height: 6,
),
StreamBuilder(
stream: ref.onValue,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData &&
!snapshot.hasError &&
snapshot.data.snapshot.value != null) {
lists.clear();
DataSnapshot dataValues = snapshot.data.snapshot;
Map<dynamic, dynamic> values = dataValues.value as Map;
values.forEach((key, values) {
lists.add(values);
});
return new ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Card(
margin: EdgeInsets.fromLTRB(2, 2, 2, 2),
elevation: 20,
child: GestureDetector(
onTap: () {
String imageurl = lists[index]["image"];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FullScreenImageViewer(
imagurl: imageurl,
),
));
},
child: Padding(
padding: EdgeInsets.all(5),
child: Container(
width: 400,
child: Image(
image:
NetworkImage(lists[index]["image"]),
),
),
),
),
),
],
);
},
);
}
return Container();
},
),
]),
),
);
You can remove the single child scroll view, i believ the problem here is because you are using a column and the listview is not expanding to the whole screen. If you want to make sure the listview occupy the all the space remaining you can use the Flex and expanded widget.
Flex can work like a column or row depending on which direction you are providing it with. anything that is placed here behave exactly like when they is placed in the column or row except for Expanded, as they fill the remainning space.
I've changed your code a bit here to accomodate the Flex and Expanded widget (you just need to readd your logic and the streambuilder to make it work)
return Scaffold(
body: Flex(direction: Axis.vertical, children: [
const SizedBox(
height: 6,
),
Expanded(
// Change the children to stream builder if neccesary
child: ListView.builder(
shrinkWrap: true,
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Card(
margin: const EdgeInsets.all(2),
elevation: 20,
child: GestureDetector(
onTap: () {
// ACTION HERE
},
child: const Padding(
padding: EdgeInsets.all(5),
child: Image(
image: NetworkImage("https://picsum.photos/200/300"),
),
),
),
),
],
);
},
),
)
]),
);
There's a property within listView() that tells it which irection the overflow is so as to scroll. Set it to
scrollDirection: Axis.horizontal

Flutter : RefreshIndicator with ListView Scroll

i have ListView. and listview have many item. Scroll through the screen.(vertical)
and if scroll position is Top, i want to RefreshIndicator work.
i don't know what i have to do..
now, only worked listview scroll. but when scroll position is Top, not work RefreshIndicator..
this is my code..
#override
Widget build(BuildContext context) {
return FutureBuilder<List<BoadModel>>(
future: getData(),
builder: (context, snapshot) {
List<BoadModel> dataList = snapshot.data ?? [];
if (snapshot.hasError) print(snapshot.error);
return RefreshIndicator(
onRefresh: () async {
setState(() {});
},
child: SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Opacity(
opacity: 0.0,
child: ElevatedButton(
onPressed: () {}, child: Text("button"))),
Text(getCategoryName(widget.categoryPage)),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WriteBoadPage(
category: widget.categoryPage,
),
),
);
},
child: Text("글쓰기"))
],
),
snapshot.hasData
? Column(
children: [
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: dataList.length,
itemBuilder: (BuildContext context, int index) {
return ListViewItem(
title: dataList[index].title,
nickname: dataList[index].nickname,
time: dataList[index].time,
view: dataList[index].view,
commentCount: dataList[index].comment);
},
),
Row(
children: [Text("dafs")],
)
],
)
: Center(
child: CircularProgressIndicator(),
)
],
),
),
);
},
);
}
I found a solution but there is another problem.
The problem is that I have SingleChildScrollView already in parent widget like shown below:
return SingleChildScrollView( //have SingleChildScrollView already
child: Column(
children: [
RefreshIndicator(
child: SingleChildScrollView(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListViewItem();
},
),
),
onRefresh: () async {}),
],
),
);
So I did it like shown below:
#override
Widget build(BuildContext context) {
return RefreshIndicator(
child: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListViewItem();
},
),
],
),
),
onRefresh: () async {},
);

How to use PageView with Stack?

I'm new to Flutter and I like the PageView widget, but how do I always have an AppBar or other elements on top?
Now PageView is changing the entire page, along with the AppBar, how can you pin it? To make the pages scroll under the AppBar
Scaffold(
body: Stack(
children: [
Padding(
padding: EdgeInsets.only(top: 50),
child: Container(
width: double.infinity,
height: 100,
color: Colors.blue,
),
),
FutureBuilder(
future: _futureMenu,
builder: (context, snapshot){
if(snapshot.hasData){
return PageView.builder(
itemBuilder: (context, position) {
return PageForPosition();
},
itemCount: snapshot.data.length, // Can be null
);
} else if (snapshot.hasError){
}
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
),
],
),
)
Place the AppBar widget in scaffold appBar parameter.
Scaffold(
appBar: AppBar(),//<-- Move appbar here.
body: Stack(
children: [
FutureBuilder(
future: _futureMenu,
builder: (context, snapshot){
if(snapshot.hasData){
return PageView.builder(
itemBuilder: (context, position) {
return PageForPosition();
},
itemCount: snapshot.data.length, // Can be null
);
} else if (snapshot.hasError){
return Center(child:Text('Error'));
}
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
),
],
),
)
Check this dart pad.
You could try use sliverAppbar code like this
SliverAppBar(
expandedHeight: 300.0,
pinned: true,
Pinned allows it to stay fixed to the top if you need additional help on this way of creating an app bar let me know happy to help further explain
You can use CustomScrollView like below to gain your UI and effect.
CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
pinned: true,
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Demo'),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('Grid Item $index'),
);
},
childCount: 20,
),
),
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 9)],
child: Text('List Item $index'),
);
},
),
),
],
)

How to make the future widget auto load the data when there is connectivity

I am trying to make a product info app, I use a future builder to build the category list.
I am facing two problems
1. when the app is initially offline and then become online it doesn't load the data.
2. Is there any way to get the length of snapshots.
I will paste the code below:
FutureBuilder(
future: getAllCategory(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Center(
child: Container(
child: CircularProgressIndicator(),
),
);
} else {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categorylist.length != 0 || categorylist.length!= null ? categorylist.length:0,
shrinkWrap: true,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () async {
pr.show();
print('clicked custom category');
print(categorylist[index].catName);
print(categorylist[index].catId);
await getAllProductsInCategory(categorylist[index].catId);
setState(() {
catId = categorylist[index].catId;
myinitlist.clear();
myinitlist = List.from(productList);
pr.hide();
_selectedIndex = index;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Card(
color: _selectedIndex != null && _selectedIndex == index
? selectedColor
: defColor,
elevation: _selectedIndex != null && _selectedIndex == index
? 4.0
: 1.0,
child: Center(
child: Padding(
padding: const EdgeInsets.all(3.0),
child: Container(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Column(
children: <Widget>[
Image.network(
categorylist[index].catThumbnail,
width: 80.0,
height: 50.0,
scale: 1.0,
),
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Text(
categorylist[index].catName,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black, fontSize: 10.0, fontWeight: FontWeight.w500),
),
)
],
),
),
),
),
),
),
],
),
);
});
}
},
),
I think if there any way to get the length of snapshots then i can resolve my first issue.
I changed the code like this
FutureBuilder(
future: getAllCategory(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: Container(
child: CircularProgressIndicator(),
),
);
} else {
print('snapshot length ${snapshot.data.length}');
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.length,
shrinkWrap: true,
itemBuilder: (context, index) {
}