问题描述
最近几天我一直在为正确的 futurebuilder 定位而苦苦挣扎。我使用 syncfusion_calendar 包来显示来自我的 API 的 json 数据,每次用户更改日历月时我都会调用一个新的请求到 API。问题是用户没有被告知正在进行的数据下载,我很乐意通过在加载时显示 CircularProgressIndicator 而不是日历来做到这一点。
我的 pubspec 文件以防万一:
name: Flutter_viaapp_startmenu
description: A new Flutter application.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots,like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in Flutter
# build by specifying --build-name and --build-number,respectively.
# In Android,build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS,build-name is used as CFBundleShortVersionString while build-number used as CFBundLeversion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
firebase_core: ^0.5.0+1
cloud_firestore: ^0.14.4
firebase_messaging: ^7.0.3
firebase_in_app_messaging: 0.2.3
webview_Flutter: ^1.0.7
Flutter_staggered_grid_view: ^0.3.3
easy_localization: ^2.3.2
intl: ^0.16.1
http: ^0.12.2
syncfusion_Flutter_calendar: ^18.3.51
shared_preferences: ^0.5.12
Flutter_local_notifications: ^3.0.3
Flutter_localizations:
sdk: Flutter
Flutter:
sdk: Flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0
dev_dependencies:
Flutter_test:
sdk: Flutter
# For information on the generic Dart part of this file,see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
Flutter:
# The following line ensures that the Material Icons font is
# included with your application,so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application,add an assets section,like this:
assets:
- assets/menu.jpg
- assets/welcome.jpg
- assets/translations/en.json
- assets/translations/lv.json
# An image asset can refer to one or more resolution-specific "variants",see
# https://Flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies,see
# https://Flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application,add a fonts section here,# in this "Flutter" section. Each entry in this list should have a
# "family" key with the font family name,and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,# see https://Flutter.dev/custom-fonts/#from-packages
我的主日历文件:
import 'dart:async';
import 'dart:convert';
import 'package:Flutter/cupertino.dart';
import 'package:Flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:syncfusion_Flutter_calendar/calendar.dart';
import 'package:intl/intl.dart';
class Lecture_graph extends StatefulWidget {
Lecture_graph({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => _MyLecturesGraphState();
}
class _MyLecturesGraphState extends State<Lecture_graph> {
Future<List<Lecture>> _future;
List<Lecture> lectures;
DateTime _selectedDate = new DateTime.Now();
List<LectureTime> _times;
//Todo make this empty after SO post
var coursecode = "IT3";
@override
void initState() {
_selectedDate = new DateTime(
_selectedDate.year,_selectedDate.month,15,_selectedDate.hour,_selectedDate.minute,_selectedDate.second,_selectedDate.millisecond,_selectedDate.microsecond);
_future = downloadData();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(coursecode + " | Lectures"),actions: [
LecturesNavigationControls(),],),body: lectureGraphList());
}
Future<String> _checkSavedCourse() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String _coursecode = prefs.getString('savedCourse');
if (_coursecode == "" || _coursecode == null) {
Navigator.push(
context,MaterialPageRoute(builder: (context) => CourseSelectionPage()),);
return null;
} else {
return _coursecode;
}
}
Widget lectureGraphList() {
return FutureBuilder<List<Lecture>>(
future: _future,builder: (BuildContext context,AsyncSnapshot<List<Lecture>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SizedBox(
child: const Expanded(
child: Center(child: const CircularProgressIndicator())),width: 100,height: 100,);
} else {
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
else
return showLectures(lectures);
}
},);
}
//THIS FUNCTION IS CALLED EVERY TIME TO DOWNLOAD NEW DATA FROM API
Future<List<Lecture>> downloadData() async {
//get saved course
if (coursecode == "" || coursecode == null) {
coursecode = await _checkSavedCourse();
//debug
print('courscode recieved from sharedprefs');
}
//if there is no date selected,select today
if (_selectedDate == null) _selectedDate = new DateTime.Now();
//build request URL
var requestURL =
'https://lekcijas.va.lv/lekcijas_android/getMonthLectures.PHP?date=' +
DateFormat('yyyy-MM').format(_selectedDate) +
"&breaks&program=" +
coursecode;
//wait for response
var response = await http.get(requestURL);
var data = json.decode(response.body)["result"];
//clear array after each request
if (lectures != null) lectures.clear();
try {
//create lectures from json response
lectures = List<Lecture>.from(data.map((x) => Lecture.fromJson(x)));
_getDataSource(lectures);
} catch (e) {
print(e.toString());
}
return Future.value(lectures);
}
Widget showLectures(List<Lecture> lectures) {
return Card(
child: Row(
children: [
Expanded(
child: SfCalendar(
view: CalendarView.month,firstDayOfWeek: 1,onViewChanged: (ViewChangedDetails details) {
if (_selectedDate.month != details.visibleDates[15].month) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_selectedDate = details.visibleDates[15];
setState(() {
//CALENDAR MONTH CHANGE IS CALLED HERE
downloadData();
});
});
}
},dataSource: LectureTimeDataSource(_times),monthViewSettings: MonthViewSettings(
appointmentdisplayMode:
MonthAppointmentdisplayMode.indicator,showAgenda: true,agendaStyle: AgendaStyle(
appointmentTextStyle:
TextStyle(color: Colors.black))),showNavigationArrow: true))
],);
}
void _getDataSource(List<Lecture> lectures) {
var lectureTimes = <LectureTime>[];
lectures.forEach((element) {
lectureTimes.add(LectureTime(
(element.classroom + " " + element.lecture),DateTime.parse(element.datums + " " + element.start),DateTime.parse(element.datums + " " + element.end),hexToColor(element.color),false));
});
setState(() {
_times = lectureTimes;
});
}
}
class LecturesNavigationControls extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
IconButton(
//Todo find normal icon
icon: const Icon(Icons.wheelchair_pickup),onpressed: () {
Navigator.push(
context,);
},);
}
}
class LectureTimeDataSource extends CalendarDataSource {
LectureTimeDataSource(List<LectureTime> source) {
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments[index].from;
}
@override
DateTime getEndTime(int index) {
return appointments[index].to;
}
@override
String getSubject(int index) {
return appointments[index].eventName;
}
@override
Color getColor(int index) {
return appointments[index].background;
}
@override
bool isAllDay(int index) {
return appointments[index].isAllDay;
}
}
class LectureTime {
LectureTime(
this.eventName,this.from,this.to,this.background,this.isAllDay);
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}
Color hexToColor(String code) {
return new Color(int.parse(code.substring(1,7),radix: 16) + 0xFF000000);
}
class Lecture{
final String programs;
final String lecture;
final String lecturer;
final String start;
final String end;
final String classroom;
final String color;
final String datums;
Lecture({this.programs,this.lecture,this.lecturer,this.start,this.end,this.classroom,this.color,this.datums});
factory Lecture.fromJson(Map<String,dynamic> json) {
return Lecture(
programs: json['nodala'] as String,lecture: json['kuRSS'] as String,lecturer : json['lektors'] as String,start: json['sakums'] as String,end: json['beigas'] as String,classroom: json['nosaukums'] as String,color: json['iela'] as String,datums: json['datums'] as String,);
}
}
class LectureTime {
LectureTime(
this.eventName,this.isAllDay);
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}
请使用“IT3”字符串作为 API 的课程代码。 API 请求网址示例 here
解决方法
您可以添加一个名为downloadingData 的变量并将其默认设置为false。然后,在调用 downloadData() 之前将其设置为 true,当函数完成时,将其设置回 false。 最后,在 build 方法中: 孩子:正在下载数据? CircularProgressIndicator() : SfCalendar(...)
,根据提供的信息和代码片段,我们进行了检查,您的要求是“在加载日历时显示 CircularProgressIndicator”。我们准备了一个简单的示例,用于加载循环进度指示器并将在线数据加载到日历。请从以下链接中找到示例,
此外,我们有一个 KB 文档,用于通过简单的加载文本消息将在线数据加载到 Flutter 日历。同样,您将使用 CircularProgressIndicator。
我们希望以上示例和知识库对您有所帮助。如果您需要进一步的帮助,请告诉我们。