I am having a custom widget, where I have updated my list of data in the horizontal and vertical drag end callback. In that call back, I have returned and updated the data using the FutureBuilder. But the method returned from future event of FutureBuilder called twice.
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late List<SampleData> chartData;
@override
void initState() {
getChartData();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
child: LoadMoreWidget(
data: chartData, loadMoreViewBuilder: onLoadMoreWidgetCalled),
));
}
Widget onLoadMoreWidgetCalled(BuildContext context) {
return FutureBuilder(
future: updateData(),
builder: (context, snapshot) {
if (snapshot.hasData && !snapshot.hasError) {
return Container();
} else {
return getProgressIndicator();
}
});
}
List<SampleData> getChartData() {
chartData = [
SampleData(0, 42),
SampleData(1, 47),
SampleData(2, 33),
SampleData(3, 49),
SampleData(4, 54),
SampleData(5, 41),
SampleData(6, 58),
SampleData(7, 51),
SampleData(8, 98),
SampleData(9, 41),
SampleData(10, 53),
SampleData(11, 72),
SampleData(12, 86),
SampleData(13, 52),
SampleData(14, 94),
SampleData(15, 92),
SampleData(16, 86),
SampleData(17, 72),
SampleData(18, 94)
];
return chartData;
}
Widget getProgressIndicator() {
return Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.only(bottom: 22),
child: Container(
width: 50,
alignment: Alignment.centerRight,
decoration: BoxDecoration(
gradient: LinearGradient(colors: <Color>[
Colors.white.withOpacity(0.0),
Colors.white.withOpacity(0.74)
], stops: const <double>[
0.0,
1
])),
child: const SizedBox(
height: 35,
width: 35,
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(Colors.blueGrey),
backgroundColor: Colors.transparent,
strokeWidth: 3)))));
}
Future<List<SampleData>> updateData() async {
for (int i = 0; i < 2; i++) {
var newIndex = chartData[chartData.length - 1].x + 1;
chartData.add(SampleData(newIndex, (Random().nextInt(60) + 30)));
}
await Future.delayed(const Duration(seconds: 1), () {});
return chartData;
}
}
class SampleData {
SampleData(this.x, this.y);
final int x;
final num y;
}
class LoadMoreWidget extends StatefulWidget {
const LoadMoreWidget(
{Key? key, required this.data, required this.loadMoreViewBuilder})
: super(key: key);
final List<dynamic> data;
final LoadMoreViewBuilderCallback loadMoreViewBuilder;
@override
State<LoadMoreWidget> createState() => _LoadMoreWidgetState();
}
class _LoadMoreWidgetState extends State<LoadMoreWidget> {
@override
Widget build(BuildContext context) {
List<dynamic> data = widget.data;
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return GestureDetector(
onHorizontalDragEnd: (DragEndDetails details) => {
(widget.loadMoreViewBuilder(context) as FutureBuilder)
.future!
.whenComplete(
() => {data = widget.data, setState(() => {})})
},
onVerticalDragEnd: (DragEndDetails details) => {
(widget.loadMoreViewBuilder(context) as FutureBuilder)
.future!
.whenComplete(
() => {data = widget.data, setState(() => {})})
},
child: Stack(children: [
ListView.builder(
itemBuilder: (context, index) {
return Card(
child: Row(
children: [
Text('x:' + data[index].x!.toString()),
Text('y:' + data[index].y!.toString()),
],
));
},
itemCount: widget.data.length,
),
(widget.loadMoreViewBuilder(context) as FutureBuilder)
.builder(context, const AsyncSnapshot.nothing())
]));
});
}
}
typedef LoadMoreViewBuilderCallback = Widget Function(BuildContext context);