Scroll not working in vertical list created using ListView? - flutter

I've created a vertical list inside a scrollable container. But the issue I'm facing is that the list is not scrolling.
This is the component which creates the parent container.
class _MainPageState extends State<MainPage> {
SharedPreferences sharedPreferences;
String _date = "Today";
#override
void initState() {
super.initState();
this.checkLoginStatus();
}
checkLoginStatus() async {
sharedPreferences = await SharedPreferences.getInstance();
if (sharedPreferences.getString("token") == null) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) => Login(),
),
(Route<dynamic> route) => false,
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: loggedInBar(sharedPreferences, context),
drawer: appDrawer(sharedPreferences, context),
body: SingleChildScrollView(
child: Container(
decoration: BoxDecoration(
color: hexToColor("#FFFFFF"),
),
child: Column(
children: <Widget>[
hero(),
SizedBox(height: 10),
Container(
padding: const EdgeInsets.fromLTRB(30, 20, 30, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
customText(
'$_date',
"#000000",
"26.0",
TextAlign.center,
"Roboto Black",
FontWeight.w900,
),
OutlineButton(
child: Container(
alignment: Alignment.center,
height: 42.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
customText(
"CHOOSE DAY",
"#EC2F3C",
"18",
TextAlign.center,
"Roboto Bold",
FontWeight.w800,
),
Icon(
Icons.date_range,
size: 22.0,
color: hexToColor("#EC2F3C"),
),
],
),
)
],
),
],
),
),
onPressed: () {
DatePicker.showDatePicker(context,
theme: DatePickerTheme(
containerHeight: 210.0,
),
showTitleActions: true,
minTime: DateTime(
DateTime.now().year - 100,
DateTime.now().month,
DateTime.now().day,
),
maxTime: DateTime(
DateTime.now().year - 17,
DateTime.now().month,
DateTime.now().day,
), onConfirm: (date) {
print('confirm $date');
var dateString = date;
var formattedDate = Jiffy(dateString).yMMMd;
setState(() {
_date = formattedDate;
});
}, currentTime: DateTime.now(), locale: LocaleType.en);
},
color: hexToColor("#efefef"),
splashColor: hexToColor("#efefef"),
highlightElevation: 2,
borderSide: BorderSide(
color: hexToColor("#EC2F3C"),
width: 2,
),
highlightedBorderColor: hexToColor("#EC2F3C"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(3),
),
),
],
),
),
AllEvents(), // the widget which creates the list(mentioned below)
SizedBox(height: 30),
footer(),
],
),
),
),
);
}
}
The widget which creates the list is this.
class _AllEventsState extends State<AllEvents> {
final String url = "<api url>";
List data;
#override
void initState() {
super.initState();
this.getAllEvents();
}
createRoute(id) {
Navigator.pushNamed(context, '/eventdetail', arguments: id);
}
Future<String> getAllEvents() async {
var response = await http.get(
Uri.encodeFull(url),
headers: {"Accept": "application/json"},
);
setState(() {
var convertDataToJson = jsonDecode(response.body);
data = convertDataToJson["events"];
});
return "Success";
}
#override
Widget build(BuildContext context) {
ScrollController _controller = new ScrollController();
return Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
physics: const AlwaysScrollableScrollPhysics(),
controller: _controller,
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext cont, int index) {
// format date
var dateString = data[index]["eventDate"];
var eventDate = Jiffy(dateString).MMMEd;
if (data == null) {
return Center(
child: Container(
padding: const EdgeInsets.fromLTRB(30, 20, 30, 20),
child: CircularProgressIndicator(),
),
);
} else {
return Container(
padding: const EdgeInsets.fromLTRB(30, 7, 30, 7),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new InkWell(
onTap: () {
createRoute(data[index]['_id']);
},
child: Card(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: hexToColor("#EBEBEB"),
),
borderRadius: BorderRadius.circular(8.0),
),
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
customText(
eventDate.toString(),
"#000000",
"20.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
customText(
"10, 9",
"#000000",
"20.0",
TextAlign.right,
"Roboto Black",
FontWeight.w900,
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: customText(
"${data[index]['city']} | ${data[index]['arenaName']} | ${data[index]['categories'][0]['title']}",
"#000000",
"18.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
),
],
),
],
),
),
),
),
],
),
),
);
}
},
),
);
}
}
The scroll is only working on touching outside the list area and once the list area covers the entire screen I'm unable to scroll the page further. I think I'm doing many mistakes here as I'm a noob in flutter. I'm unable to wrap my head around what I'm doing wrong as I don't think this is how it's supposed to work.
Please help me fix this issue. Any help would be great? Thank you

change the scroll physics of list to NeverScrollableScrollPhysics
ListView.builder(
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
controller: _controller,
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext cont, int index) {
// code for building list item
});

Related

Screen does not update even though build function is running flutter

So I have created a chat app which draws from a pusher client. Whenever there is a new message, the build function does rebuild, and I believe the widget list does change, but there is no update on the screen. How do I fix this ?
Widget build(BuildContext context) {
// print(messageWidgetList.length);
return Scaffold(
backgroundColor: AppColors.lightGrey,
appBar: AppBar(
backgroundColor: Colors.transparent,
title: Text(
messageTo,
style: TextStyle(
color: AppColors.white,
fontSize: 22,
),
),
),
body: Stack(
children: [
Padding(
padding:
const EdgeInsets.only(top: 12, left: 12, right: 12, bottom: 70),
child: ValueListenableBuilder<List<Widget>>(
valueListenable: messageWidgetList,
builder: (context, value, widget) {
print("Updated");
print(value.length);
// print(widget);
return ListView.builder(
// controller: scrollController,
physics: AlwaysScrollableScrollPhysics(),
reverse: true,
addAutomaticKeepAlives: true,
itemCount: value.length,
itemBuilder: (ctx, index) {
// print(index);
return value[index];
},
);
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (xFilesImages.isNotEmpty)
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: xFilesImages.map<Widget>((element) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: SizedBox(
height: 100,
width: 80,
child: Image.file(
File(element.path),
frameBuilder:
(ctx, child, frame, wasSynchronouslyLoaded) {
return SizedBox(
width: MediaQuery.of(ctx).size.width,
height: MediaQuery.of(ctx).size.height,
child: Stack(
children: [
Align(
alignment: Alignment.topRight,
child: Container(
height: 25,
width: 25,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.lightestGrey,
),
child: FittedBox(
child: GestureDetector(
onTap: () {
xFilesImages.remove(element);
setState(() {});
},
child:
const Icon(Icons.cancel)),
),
),
),
child
],
),
);
},
),
),
);
}).toList(),
),
),
const SizedBox(height: 5),
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: Padding(
padding:
const EdgeInsets.only(left: 10, bottom: 10, right: 10),
child: Container(
// height: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppColors.darkGrey,
),
child: TextFormField(
// expands: true,
style: TextStyle(color: AppColors.white),
focusNode: messageFocusNode,
controller: messageController,
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(
right: 8, left: 8, top: 14),
prefixIcon: InkWell(
onTap: () async {
if (!(await Permission.camera.isGranted)) {
await Permission.camera.request();
await Permission.photos.request();
}
ImagePicker _picker = ImagePicker();
xFilesImages =
await _picker.pickMultiImage() ?? [];
print("Got xFiles");
print(xFilesImages.length);
for (XFile xFile in xFilesImages) {
print(xFile.name);
print(xFile.path);
}
setState(() {});
},
child: Icon(
Icons.attachment,
size: 34,
color: AppColors.lightestGrey,
),
),
suffixIcon: GestureDetector(
onTap: () async {
//TODO: When you wake up, you have implemented picking images. Work on displaying picked images and then sending them
// loading = true;
// messageController.text = '';
if (messageController.text.isNotEmpty ||
xFilesImages.isNotEmpty) {
messageFocusNode.unfocus();
// messageWidgetList.add(sentMessage(
// {"message": messageController.text}));
setState(() {});
print("Sent button clicked");
ApiProvider.sendMessage(
widget.userModel.bearerToken,
widget.senderPhone.phoneNumbers.first,
messageTo,
messageController.text,
xFilesImages);
// loading = false;
messageController.text = '';
xFilesImages = [];
setState(() {});
}
},
child: const Icon(
Icons.send,
size: 30,
color: const Color(0xFF004b77),
),
),
fillColor: AppColors.lightGrey,
hintText: "Enter message...",
hintStyle:
TextStyle(color: AppColors.lightestGrey)),
),
),
),
),
],
),
),
if (loading)
Container(
height: double.infinity,
width: double.infinity,
color: AppColors.lightGrey.withOpacity(0.3),
child: Center(
child: SpinKitChasingDots(
color: AppColors.blue,
)),
)
],
),
);
}
Bad, does not work
static final List<Widget> items= [];
Widget build(BuildContext context) {
return ListView(children: items); // <-- look here
}
Good, does update properly
static final List<Widget> items= [];
Widget build(BuildContext context) {
return ListView(children: [...items]); // <-- look here
}
Grandious with the little extra mile
static final List<Widget> items= [];
Widget build(BuildContext context) {
return ListView(children: <Widget>[...items]); // <-- look here
}
setState needs a brand new object to update properly. It does not look into a List like here if something changed in there.

How to remove build side effects in this context, using Staggered Grid View Builder Flutter?

I am trying to create the build method without side effects (without blinking). I solved this problem using StatefulBuilder, but I read that I should rebuild 1000x times without any change or effect.
The Staggered Grid View Builder Widget are rebuilt when the keyboard is opening, or whenever I open again the page, or add/remove an item from it. That's good, normally, but with side effects like you see below. Maybe there is any solution to animate the remove/add functionality, or the infinite reloading and keep the rest of the items in cache. So I need to limit the builder recreate inside Grid View Builder?
On other applications I don't see this ugly "blinking". Where is the problem and how can I solve it? I used Animation Limiter but it's not working for me, neither PrecacheImage, somehow I need to rebuild without blink (first items).
My code:
class VisionBoard extends StatefulWidget {
const VisionBoard({Key? key}) : super(key: key);
#override
_VisionBoardState createState() => _VisionBoardState();
}
class _VisionBoardState extends State<VisionBoard> with SingleTickerProviderStateMixin {
ScreenshotController screenshotController = ScreenshotController();
String saveGoalsButtonText = "SAVE GOALS";
String wallpaperButtonText = "CREATE WALLPAPER";
String saveWallpaperButtonText = "SAVE";
bool createWallpaper = false;
bool isWallpaperCreated = false;
late File imageFile;
late String newImage;
late Uint8List imageRaw;
int noOfImages = 0;
late Uint8List wallpaperBytes;
String title = "My Vision Board";
String goals = "";
late List<String> visions = <String>[];
final TextEditingController _textFieldController = TextEditingController();
final TextEditingController _goalsController = TextEditingController();
static final _formKey = GlobalKey<FormState>();
#override
void initState() {
super.initState();
loadVisionBoardTitleAndImages();
}
void loadVisionBoardTitleAndImages() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//await prefs.clear();
setState(() {
_textFieldController.text = prefs.getString('titlu') ?? title;
visions = prefs.getStringList('visions') ?? <String>[];
_goalsController.text = prefs.getString('goals') ?? goals;
});
}
void _removeVisions(int index) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
isButtonDisabled=true;
visions.removeAt(index);
prefs.setStringList('visions', visions);
createWallpaper = false;
wallpaperButtonText = "CREATE WALLPAPER";
isWallpaperCreated = false;
});
await CreateWallpaperLayouts().createWallpaper(visions).then((value) {
setState(() {
wallpaperBytes = value;
wallpaper = Image.memory(wallpaperBytes);
precacheImage(wallpaper.image, context);
isButtonDisabled=false;
});
});
}
#override
Widget build(BuildContext context) {
return Sizer(
builder: (context, orientation, deviceType) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
child: Scaffold(
body: AnimationLimiter(
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/background-marmura.jpeg"), fit: BoxFit.cover)),
child: SafeArea(
child: SingleChildScrollView(
child: Container(
margin: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
children: [
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Row(
children: [
Flexible(
child: Text(_textFieldController.text,
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 21,
color: Color(0xff393432),
),
),
),
IconButton(
icon: const Icon(
Icons.edit,
size: 21,
color: Color(0xff393432),
),
onPressed: () {
showAlertDialog(context, setState);
},
)
]);
}
),
const SizedBox(height: 5),
GridView.builder(
clipBehavior: Clip.none,
physics: const ScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: SizeConfig.screenWidth!/3,),
itemCount: (visions.length == 12) ? visions.length : visions.length + 1,
itemBuilder: (BuildContext ctx, index) {
if (index < visions.length) {
return AnimationConfiguration.staggeredGrid(
position: index,
duration: const Duration(milliseconds: 1000),
columnCount: 3,
child: ScaleAnimation(
child: FadeInAnimation(
child: OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: index < visions.length, //bind with the boolean
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 25.w,
height: 25.w,
decoration: BoxDecoration(
image: DecorationImage(
image: CleverCloset.imageFromBase64String(visions[index]).image,
fit: BoxFit.fill),
borderRadius: const BorderRadius.all(
Radius.circular(
5.0) // <--- border radius here
),
),
),
Positioned(
top:0,
right:0,
child: ClipOval(
child: InkWell(
onTap: () {
_removeVisions(index);
},
child: Container(
padding: const EdgeInsets.all(5),
color: Colors.white,
child:
const Icon(
Icons.delete,
size: 16,
color: Color(0xff393432)),
),
),
),
),
],
clipBehavior: Clip.none,
),
),
),
),
);
}
else if(index<12){
return InkWell(
onTap: () {
_openGallery(context);
},
child:
Stack(
alignment: Alignment.center,
children:[
Container(
width: 25.w,
height: 25.w,
decoration:
BoxDecoration(
border: Border.all(color: const Color(0xff393432)),
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
),
child:
const Icon(
Icons.add,
size: 25,
color: Color(0xff393432),
)
),
],
),
);
}
else {
return Container(color: Colors.red);
}
}
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: const [
Text("You can add up to 12 pictures.",
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.italic,
),),
],
),
const SizedBox(height: 10),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column (
children: [
if(visions.isNotEmpty && visions.length>1 && !isWallpaperCreated) Row(
children: [
SizedBox(
width: 50.w,
child: OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value)
enabled: !isWallpaperCreated &&
visions.isNotEmpty && visions.length > 1,
child: OutlinedButton(
onPressed: visions.isNotEmpty &&
visions.length > 1 ? () async{
setState(() {
wallpaperButtonText = "CREATING...";
//_createWallpaper();
});
wallpaperBytes = await CreateWallpaperLayouts().createWallpaper(visions);
setState(() {
noOfImages = visions.length;
isWallpaperCreated = true;
createWallpaper = true;
});
//Navigator.pushReplacementNamed(context, '/masterclasses');
} : null,
style: OutlinedButton.styleFrom(
primary: const Color(0xffE4BCB4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
18.0),
),
side: const BorderSide(
width: 3, color: Color(0xffE4BCB4)),
),
child: Text(
wallpaperButtonText,
style: const TextStyle(
color: Color(0xff393432),
fontSize: 14,
fontWeight: FontWeight.w700,
)
),
),
),
),
],
),
const SizedBox(height:40),
if(createWallpaper==true) OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: createWallpaper, //bind with the boolean
child: Row(
children: const [
Flexible(
child: Text("Wallpaper",
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 21,
color: Color(0xff393432),
),
),
),
],
),
),
if(createWallpaper==true) const SizedBox(height:15),
if(createWallpaper==true)
OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: createWallpaper,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children:[ Container(
width: 50.w,//double.infinity,
height: 50.h,//SizeConfig.screenHeight,
decoration: BoxDecoration(
image: DecorationImage(
image: Image.memory(wallpaperBytes).image,
fit: BoxFit.fill,
)
),
//child: CreateWallpaperLayouts().createWallpaper(visions),
),],
),
),
if(createWallpaper==true) const SizedBox(height:10),
if(createWallpaper==true) StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: createWallpaper,
child: Row(
children: [
SizedBox(
width: 50.w,
child: OutlinedButton(
onPressed: () {
_saveWallpaper(wallpaperBytes);
setState(() {
saveWallpaperButtonText = "SAVED!";
});
Future.delayed(const Duration(milliseconds: 1300), () {
setState(() {
saveWallpaperButtonText = "SAVE";
});
});
//Navigator.pushReplacementNamed(context, '/masterclasses');
},
style: OutlinedButton.styleFrom(
primary: const Color(0xffE4BCB4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
side: const BorderSide(width: 3, color: Color(0xffE4BCB4)),
),
child: Text(
saveWallpaperButtonText,
style: const TextStyle(
color: Color(0xff393432),
fontSize: 14,
fontWeight: FontWeight.w700,
)
),
),
),
const SizedBox(width: 10),
],
),
);
}
),
if(createWallpaper==true) const SizedBox(height:50),
Row(
children: const [
Flexible(
child: Text("Goals & Affirmations",
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 21,
color: Color(0xff393432),
),
),
),
],
),
],
);
}
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: const [
Text("Add goals and affirmations.",
style: TextStyle(
fontSize: 15,
),),
],
),
const SizedBox(height: 10),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
children: [
Card(
elevation: 0,
color: const Color(0xffEFEFEF),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
key: _formKey,
controller: _goalsController,
maxLines: 8,
decoration: const InputDecoration(border: InputBorder.none),
),
)
),
const SizedBox(height: 10),
Row(
children: [
Container(
width: 50.w,
margin: const EdgeInsets.fromLTRB(0, 0, 0, 40),
child: OutlinedButton(
onPressed: () async{
setState(() {
saveGoalsButtonText = "SAVED!";
});
Future.delayed(const Duration(seconds: 1), () {
setState(() {
saveGoalsButtonText = "SAVE GOALS";
});
});
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
goals = _goalsController.text;
prefs.setString('goals', goals);
});
//Navigator.pushReplacementNamed(context, '/masterclasses');
},
style: OutlinedButton.styleFrom(
primary: const Color(0xffE4BCB4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
side: const BorderSide(width: 3, color: Color(0xffE4BCB4)),
),
child: Text(
saveGoalsButtonText,
style: const TextStyle(
color: Color(0xff393432),
fontSize: 14,
fontWeight: FontWeight.w700,
)
),
),
),
],
),
],
);
}
),
],
),
),
),
),
),
),
),
);
}
);
}
}

How to Fix List Items are automatically changing their positing in flutter?

I am calling API data inside Listview. builder in flutter but the error I am facing is the items are changing their positions automatically.
For Example, When I load this class for the First Time the arrangement of List items is the same as required but after 30-40 seconds the List items arrangement automatically starts changing, and data showing itself randomly.
I am looking for someone who can help me to fix this issue?
For this purpose here is myClass Code.
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart'as HTTP;
import 'package:worldcup/utils/colors.dart';
class SeriesSchedulePage extends StatefulWidget {
#override
_SeriesSchedulePageState createState() => _SeriesSchedulePageState();
}
class _SeriesSchedulePageState extends State<SeriesSchedulePage> {
List<dynamic> matches = [];
var match;
getSchedule() async {
http.Response response = await http
.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
final Map parseData = await json.decode(response.body.toString());
matches = parseData['matchList']["matches"];
setState(() {
match = matches;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.primaryWhite,
appBar: AppBar(
backgroundColor: AppColors.yellow,
elevation: 0,
centerTitle: true,
leading: IconButton(
onPressed: () {
Navigator.pop(context,true);
},
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
),
title: Text(
'Schedule',
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 17),
),
),
body: Container(
child: FutureBuilder(
future: getSchedule(),
builder: (context, snapshot) {
if (match == null) {
return Center(
child: CupertinoActivityIndicator(
animating: true, radius: 15));
} else
return ListView.builder(
itemCount: matches.length,
shrinkWrap: true,
reverse: false,
itemBuilder: (context, index) {
if (matches[index]["status"] =="UPCOMING") {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
child: Container(
width: double.infinity,
child: Padding(
padding: EdgeInsets.only(left: 15, top: 7, bottom: 7, right: 15),
child: Row(
children: [
SizedBox(width: 20,),
Expanded(
flex: 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
matches[index]['name'].toString(),
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
fontWeight: FontWeight.w700, fontSize: 15),
),
SizedBox(height: 10,),
Text(
matches[index]["homeTeam"]['name'].toString(),
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
fontWeight: FontWeight.w700, fontSize: 15),
),
SizedBox(height: 10,),
Text(
matches[index]["awayTeam"]['name'].toString(),
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
fontWeight: FontWeight.w500, fontSize: 13),
),
],
),
],
),
),
],
),
),
)
);
} else {
return Center(
child: Text("No Upcoming Match in this series"),
);
}
}
);
},
),
)
);
}
}
The issue is because getSchedule() has a setState inside it. When the build method is called, getSchedule() will trigger, and since it is calling setState , the build method is being called again, causing your widgets to continuously rebuild in an infinite loop.
What you need to do is prevent such a loop from happening. I see that you are using FutureBuilder too, that is a solution but your implementation is incorrect.
What you should do is this:
Future<List<dynamic>> getSchedule() async {
http.Response response =
await http.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
final Map parseData = await json.decode(response.body.toString());
var matches = parseData['matchList']["matches"];
return matches;
}
This function returns a Future<List<dynamic>> which your future builder can use to handle the builds. For info on future builder here https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html.
Since you FutureBuilder will react to what is provided by getSchedule() when the future is complete, you do not need to use setState to rebuild.
I have modified your SeriesShedualPage here is the full code:
class SeriesSchedulePage extends StatefulWidget {
#override
_SeriesSchedulePageState createState() => _SeriesSchedulePageState();
}
class _SeriesSchedulePageState extends State<SeriesSchedulePage> {
Future<List<dynamic>> getSchedule() async {
http.Response response =
await http.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
final Map parseData = await json.decode(response.body.toString());
var matches = parseData['matchList']["matches"];
return matches;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: FutureBuilder<List<dynamic>>(
future: getSchedule(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<dynamic> matches = snapshot.data!;
return ListView.builder(
itemCount: matches.length,
shrinkWrap: true,
reverse: false,
itemBuilder: (context, index) {
if (matches[index]["status"] == "UPCOMING") {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
child: Container(
width: double.infinity,
child: Padding(
padding: EdgeInsets.only(
left: 15, top: 7, bottom: 7, right: 15),
child: Row(
children: [
SizedBox(
width: 20,
),
Expanded(
flex: 2,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
matches[index]['name'].toString(),
textScaleFactor: 0.9,
),
SizedBox(
height: 10,
),
Text(
matches[index]["homeTeam"]['name']
.toString(),
textScaleFactor: 0.9,
),
SizedBox(
height: 10,
),
Text(
matches[index]["awayTeam"]['name']
.toString(),
textScaleFactor: 0.9,
),
],
),
],
),
),
],
),
),
));
} else {
return Center(
child: Text("No Upcoming Match in this series"),
);
}
});
}
return Center(
child: CupertinoActivityIndicator(animating: true, radius: 15));
},
),
));
}
}

Flutter : Type mismatch: inferred type is String? but String was expected

I am new to coding.I am using upi_pay package in my project to make UPI payments getting error as "Type mismatch: inferred type is String? but String was expected" when I tried the build the app
I followed this article https://dev.to/dsc_ciet/adding-upi-payment-gateway-in-flutter-376c
I am new to coding, don't mind if this was a easy thing.
Please go through the below code
Thanks in advance
class PaymentScreen extends StatefulWidget {
#override
_PaymentScreenState createState() => _PaymentScreenState();
}
class _PaymentScreenState extends State<PaymentScreen> {
String _upiAddrError;
final _upiAddressController = TextEditingController();
final _amountController = TextEditingController();
bool _isUpiEditable = false;
Future<List<ApplicationMeta>> _appsFuture;
#override
void initState() {
_amountController.text =
(Random.secure().nextDouble() * 10).toStringAsFixed(2);
_appsFuture = UpiPay.getInstalledUpiApplications();
super.initState();
}
void _generateAmount() {
setState(() {
_amountController.text =
(Random.secure().nextDouble() * 10).toStringAsFixed(2);
});
}
Future<void> _onTap(ApplicationMeta app) async {
final err = _validateUpiAddress(_upiAddressController.text);
if (err != null) {
setState(() {
_upiAddrError = err;
});
return;
}
setState(() {
_upiAddrError = null;
});
final transactionRef = Random.secure().nextInt(1 << 32).toString();
print("Starting transaction with is $transactionRef");
final a = await UpiPay.initiateTransaction(
amount: _amountController.text,
app: app.upiApplication,
receiverName: "Sharad",
receiverUpiAddress: _upiAddressController.text,
transactionRef: transactionRef,
merchantCode: '7372',
);
print(a);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: ListView(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 32),
child: Row(
children: <Widget>[
Expanded(
child: TextFormField(
controller: _upiAddressController,
enabled: _isUpiEditable,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'address#upi',
labelText: 'Receiving UPI Address',
),
),
),
Container(
margin: EdgeInsets.only(left: 8),
child: IconButton(
icon: Icon(
_isUpiEditable ? Icons.check : Icons.edit,
),
onPressed: () {
setState(() {
_isUpiEditable = !_isUpiEditable;
});
},
),
),
],
),
),
if (_upiAddrError != null)
Container(
margin: EdgeInsets.only(top: 4, left: 12),
child: Text(
_upiAddrError,
style: TextStyle(color: Colors.red),
),
),
Container(
margin: EdgeInsets.only(top: 32),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _amountController,
readOnly: true,
enabled: false,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Amount',
),
),
),
Container(
margin: EdgeInsets.only(left: 8),
child: IconButton(
icon: Icon(Icons.loop),
onPressed: _generateAmount,
),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 128, bottom: 32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 12),
child: Text(
'Pay Using',
style: Theme.of(context).textTheme.caption,
),
),
FutureBuilder<List<ApplicationMeta>>(
future: _appsFuture,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return Container();
}
return GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
childAspectRatio: 1.6,
physics: NeverScrollableScrollPhysics(),
children: snapshot.data
.map((it) => Material(
key: ObjectKey(it.upiApplication),
color: Colors.grey[200],
child: InkWell(
onTap: () => _onTap(it),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
children: <Widget>[
Image.memory(
it.icon,
width: 64,
height: 64,
),
Container(
margin: EdgeInsets.only(top: 4),
child: Text(
it.upiApplication.getAppName(),
),
),
],
),
),
))
.toList(),
);
},
),
],
),
)
],
),
),
),
);
}
}
String _validateUpiAddress(String value) {
if (value.isEmpty) {
return 'UPI Address is required.';
}
if (!UpiPay.checkIfUpiAddressIsValid(value)) {
return 'UPI Address is invalid.';
}
return null;
}
You're assigning null to _upiAddrError but it's a non-nullable String.
Declare that variable as String? _upiAddrError instead of String _upiAddrError to make it nullable.

How to Get the Number of Pages in Pageview to be used in a line indicator in Flutter?

May i ask for help on how to get the number of pages inside a pageview,
similar to listview you can get the number of list via listview.length, but for pageview there is no pageview.length property that i can use,
i tried using pageview.builder but i couldnt initiate the data as a list showig an issue that i need to initiate it as an initializers?,
please help me figure it out
i need the data inside the pageview to be used inside the _lineprogressindicator, to show how many are the questionaires inside to make an indicator
here is my code
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:survey/content/thankyou.dart';
import 'package:survey/widgets/animations.dart';
import 'package:survey/widgets/buttonstyle.dart';
import 'package:survey/widgets/widgetlist.dart';
class questionaires extends StatefulWidget {
#override
_questionairesState createState() => _questionairesState();
}
class _questionairesState extends State<questionaires> {
TextStyle conqueststyle = TextStyle(
fontSize: 15, fontWeight: FontWeight.bold, color: Colors.indigo);
TextStyle questionstyle = TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
);
String titletop = 'Post Visit Patient Satisfaction';
String q1 = "Sample Question HERE";
String q2 = "Sample Question HERE";
String q3 = "Sample Question HERE";
String q4 = "Sample Question HERE";
int percentagenum = 0;
int _currValue = 1;
bool _loading;
double _progress;
final _texteditingcontroller = TextEditingController();
final _pageController = PageController(initialPage: 0, keepPage: true);
var _currentpage = 0;
List answernumbers = ["5", "4", "3", "2", "1"];
List currentselectedvalue = [];
List usingCollection1 = [
"Excellent",
"Very Good",
"Good",
"Fair",
"Poor",
];
#override
void dispose() {
super.dispose();
_texteditingcontroller.dispose();
_loading = false;
_progress = 0.0;
percentagenum = 0;
_currValue = 0;
usingTimes1 = '';
usingTimes = '';
usingTimes2 = '';
}
void initState() {
super.initState();
usingTimes1 = '';
usingTimes = '';
usingTimes2 = '';
_loading = false;
_progress = 0.0;
percentagenum = 0;
_texteditingcontroller.clear();
_currValue = 0;
}
void pageChanged(int index) {
setState(() {
_currentpage = index;
});
}
void _selectedanswers(data1, data2) {
if (_progress.toStringAsFixed(1) == '1.0') {
print(data1);
print(data2);
_texteditingcontroller.text;
}
}
void _updateProgress() {
setState(() {
_progress += 0.25;
percentagenum += 25;
if (_progress.toStringAsFixed(1) == '1.0') {
_loading = false;
_progress = 0;
percentagenum = 0;
Navigator.push(context, FadeRoute(page: thankyou()));
return;
}
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomPadding: false,
body: Padding(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 100,
height: 60,
child: Image.asset(imgtit),
),
Stack(
children: <Widget>[
Container(
child: Text(
titletop,
style: conqueststyle,
maxLines: 1,
),
),
_buildPageView(),
_lineprogressindicator()
],
)
],
),
),
),
);
}
_buildPageView() {
return Container(
height: MediaQuery.of(context).size.height / 1.25,
child: PageView(
controller: _pageController,
onPageChanged: (index) {
pageChanged(index);
},
children: <Widget>[
_emojiquestions(q1),
_selectedutton(q2),
_numberrating(q3),
_textboxquestion(q4),
],
));
}
_lineprogressindicator() {
return Positioned(
left: 0.0,
right: 0.0,
bottom: 0.0,
child: Column(
children: <Widget>[
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(50.0),
),
color: Colors.indigo,
onPressed: () {
_pageController.nextPage(
duration: kTabScrollDuration, curve: Curves.ease);
_loading = !_loading;
_updateProgress();
},
child: Icon(
Icons.check,
color: Colors.white,
size: 50,
),
),
SizedBox(
height: 10,
),
Text('%$percentagenum'),
LinearProgressIndicator(
value: _progress,
),
],
),
);
}
_emojiquestions(String quest1) {
final using = usingCollection1[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 1',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest1),
maxLines: 5,
style: conqueststyle,
),
Expanded(
child: Center(
child: Container(
height: 300,
child: ListView.separated(
separatorBuilder: (context, index) => SizedBox(height: 10),
itemCount: usingCollection1.length,
itemBuilder: (context, index) => GestureDetector(
onTapUp: (index) {
_selectedanswers(index, null);
},
child: Card(
color: usingTimes == usingCollection1[index]
? Colors.blue.withAlpha(100)
: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
SizedBox(
height: 50,
width: 70,
child: Image.asset(emojiimage[index]),
),
Text(usingCollection1[index])
],
),
Divider(
height: index < usingCollection1.length ? 1.0 : 0.0,
),
],
),
),
),
)),
),
)
],
);
}
_selectedutton(String quest1) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 1',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest1),
maxLines: 5,
style: conqueststyle,
),
Expanded(
child: Center(
child: Container(
height: 300,
child: Column(
children: List.generate(usingCollection1.length, (int index) {
final using = usingCollection1[index];
return GestureDetector(
onTap: () {
setState(() {
_currValue = index;
_selectedanswers(index, null);
usingTimes = using.identifier;
});
},
child: Card(
color: usingTimes == using.identifier
? Colors.blue.withAlpha(100)
: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Radio(
value: index,
groupValue: _currValue,
onChanged: (val) =>
setState(() => _currValue = val),
),
Text(using.displayContent)
],
),
Divider(
height:
index < usingCollection1.length ? 1.0 : 0.0,
),
],
),
));
}),
),
),
),
)
],
);
}
_numberrating(quest) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 2',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest),
maxLines: 5,
style: conqueststyle,
),
Text("**5 is the highest"),
Container(
height: MediaQuery.of(context).size.height / 12.0,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: usingCollection1.length,
itemBuilder: (context, index) {
final using = usingCollection1[index];
return GestureDetector(
onTapUp: (index) {
setState(() {
_selectedanswers(null, index);
usingTimes = using.identifier;
});
},
child: Card(
color: usingTimes == using.identifier
? Colors.blue.withAlpha(100)
: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
side: BorderSide(color: Colors.indigoAccent)),
child: Column(
children: <Widget>[
SizedBox(
height: 50,
width: 50,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
answernumbers[index],
textAlign: TextAlign.center,
style: conqueststyle,
),
],
)),
),
],
),
),
);
},
),
)
],
);
}
_textboxquestion(quest) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 2',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest),
maxLines: 5,
style: conqueststyle,
),
TextFormField(
decoration: InputDecoration(
hintText: "Your FeedBack Here",
border: OutlineInputBorder(),
),
controller: _texteditingcontroller,
maxLines: 7,
style: conqueststyle,
)
],
);
}
}
For your case were the number of elements is known beforehand, I would suggest that you store your pages in a local variable and then call length on it. A small snippet would look something like this:
class MyState extends State<MyWidget> {
List<Widget> _pages = [
Container(color: Colors.blue,),
Container(color: Colors.amber,),
];
#override
Widget build(BuildContext context) {
return MyComplexWidgetTree(
child: PageView(
controller: PageController(),
children: _pages,
),
);
}
void _myMethodThatRequiresNumberOfPages() {
int numberOfPages = pages.length;
}
}