Related
I have an app that has a splash screen and an onboarding screen. There are no errors or warnings anywhere; the app runs to show the splash screen but then crashes instead of displaying the onboarding screen.
======== Exception caught by widgets library =======================================================
The following UnsupportedError was thrown building BoardingPage(dirty, state: _BoardingScreenState#e3368):
Unsupported operation: Cannot add to an unmodifiable list
The relevant error-causing widget was:
BoardingPage BoardingPage:file:///C:/Users/Srishti/AndroidStudioProjects/App-mini-project-1/lib/splash.dart:22:78
Here's my code :
splash.dart
import 'package:flutter/material.dart';
import 'boarding_screen.dart';
class Splash extends StatefulWidget {
const Splash({Key? key}) : super(key: key);
#override
State<Splash> createState() => _SplashState();
}
class _SplashState extends State<Splash> {
#override
void initState(){
super.initState();
_navigatetohome();
}
_navigatetohome() async {
await Future.delayed(Duration(milliseconds: 2500), (){});
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => BoardingPage()));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Text('Your Scheduler',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.normal,
),
),
),
),
);
}
}
slide.dart
class Slide {
String image;
String heading;
Slide(this.image, this.heading);
}
boarding_screen.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gradient_widgets/gradient_widgets.dart';
import 'package:schedule_management/slide.dart';
import 'login_screen.dart';
class BoardingPage extends StatefulWidget {
const BoardingPage({Key? key}) : super(key: key);
#override
_BoardingScreenState createState() => _BoardingScreenState();
}
class _BoardingScreenState extends State<BoardingPage> {
int _currentPage = 0;
List<Slide> _slides = [];
PageController _pageController = PageController();
#override
void initState() {
_currentPage = 0;
_slides = [
Slide("images/slide-1.png", "Manage your time"),
Slide("images/slide-2.png", "Schedule your tasks"),
Slide("images/slide-3.png", "Never miss out on any task"),
];
_pageController = PageController(initialPage: _currentPage);
super.initState();
}
// the list which contain the build slides
List<Widget> _buildSlides() {
return _slides.map(_buildSlide).toList();
}
// building single slide
Widget _buildSlide(Slide slide) {
return Column(
children: <Widget>[
Expanded(
child: Container(
margin: const EdgeInsets.all(1),
child: Image.asset(slide.image, fit: BoxFit.contain),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 70),
child: Text(
slide.heading,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.w900,
),
),
),
const SizedBox(
height: 230,
)
],
);
}
// handling the on page changed
void _handlingOnPageChanged(int page) {
setState(() => _currentPage = page);
}
// building page indicator
Widget _buildPageIndicator() {
Row row = Row(mainAxisAlignment: MainAxisAlignment.center, children: const []);
for (int i = 0; i < _slides.length; i++) {
row.children.add(_buildPageIndicatorItem(i));
if (i != _slides.length - 1) {
row.children.add(const SizedBox(
width: 12,
));
}
}
return row;
}
Widget _buildPageIndicatorItem(int index) {
return Container(
width: index == _currentPage ? 8 : 5,
height: index == _currentPage ? 8 : 5,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: index == _currentPage
? const Color.fromRGBO(136, 144, 178, 1)
: const Color.fromRGBO(206, 209, 223, 1)),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
PageView(
controller: _pageController,
onPageChanged: _handlingOnPageChanged,
physics: BouncingScrollPhysics(),
children: _buildSlides(),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Column(
children: <Widget>[
_buildPageIndicator(),
SizedBox(height: 32,),
Container(
// see the page indicators
margin: EdgeInsets.symmetric(horizontal: 10000000),
child: SizedBox(
width: double.infinity,
child: GradientButton(
callback: () => {},
gradient: LinearGradient(colors: const [
Color.fromRGBO(11, 198, 200, 1),
Color.fromRGBO(68, 183, 183, 1)
]),
elevation: 0,
increaseHeightBy: 28,
increaseWidthBy: double.infinity,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: Text(
"",
style: TextStyle(
letterSpacing: 4,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
)),
),
SizedBox(height: 10,),
CupertinoButton(
child: Text(
"Sign In",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: Colors.grey,
),
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => LoginScreen()));
}),
SizedBox(height: 30,),
],
),
)
],
),
);
}
}
I have tried restarting Android Studio and running flutter clean but the app still crashes.
The problem probably because of the following code:
Widget _buildPageIndicator() {
Row row = Row(mainAxisAlignment: MainAxisAlignment.center, children: const []);
for (int i = 0; i < _slides.length; i++) {
row.children.add(_buildPageIndicatorItem(i));
if (i != _slides.length - 1) {
row.children.add(const SizedBox(
width: 12,
));
}
}
return row;
}
where you're trying to change the const row children. So, change it like the following code:
Widget _buildPageIndicator() {
List<Widget> children = [];
for (int i = 0; i < _slides.length; i++) {
children.add(_buildPageIndicatorItem(i));
if (i != _slides.length - 1) {
children.add(const SizedBox(
width: 12,
));
}
}
return Row(mainAxisAlignment: MainAxisAlignment.center,
children: children,
);
}
I am building a quiz app and I created a custom widget to save me a lot of time as I have a lot of questions for the quiz. Everything works apart from the scoring system. If I create multiple instances of the same widget the score will not be incremented and it will stay on 1. Is there any way I can pass each score of the widgets to a global variable in my main widget so then I can add all the scores? (I'm new to flutter).
Custom Widget
class Questions extends StatefulWidget {
final String imagePath;
final String question;
final String answer1;
final String answer2;
final String answer3;
final String answer4;
final bool iscorrectAnswer1;
final bool iscorrectAnswer2;
final bool iscorrectAnswer3;
final bool iscorrectAnswer4;
int score = 0;
bool questionsAnswered = false;
Questions(
this.imagePath,
this.question,
this.answer1,
this.answer2,
this.answer3,
this.answer4,
this.iscorrectAnswer1,
this.iscorrectAnswer2,
this.iscorrectAnswer3,
this.iscorrectAnswer4,
);
#override
_QuestionsState createState() => _QuestionsState();
}
class _QuestionsState extends State<Questions> {
disableButton() {
setState(() {
widget.questionsAnswered = true;
Quiz().score += widget.score;
});
}
#override
#override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
width: 600,
height: 600,
child: Image.asset(widget.imagePath),
),
Align(
alignment: Alignment.topCenter,
child: Padding(
padding: EdgeInsets.only(
top: 20,
),
child: Text(
widget.question,
style: TextStyle(
color: Colors.white,
fontSize: 38,
),
),
)),
Padding(
padding: EdgeInsets.only(
top: 40,
),
child: SizedBox(
width: 500,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Color(0xFF304e60),
),
),
child: Text(
widget.answer1,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
onPressed: widget.questionsAnswered == false
? () {
setState(() {
if (widget.iscorrectAnswer1 == true) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Correct!'),
),
);
disableButton();
widget.score += 1;
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text('Wrong Answer!'),
));
}
});
print(widget.iscorrectAnswer1);
print(widget.score);
}
: null),
),
)),
Padding(
padding: EdgeInsets.only(
top: 10,
),
child: SizedBox(
width: 500,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Color(0xFF565462))),
child: Text(
widget.answer2,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
onPressed: widget.questionsAnswered == false
? () {
setState(() {
if (widget.iscorrectAnswer2 == true) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Correct!'),
),
);
widget.score += 1;
} else {
disableButton();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text('Wrong Answer!'),
));
}
});
}
: null),
),
)),
Padding(
padding: EdgeInsets.only(
top: 10,
),
child: SizedBox(
width: 500,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Color(0xFF84693b))),
child: Text(
widget.answer3,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
onPressed: widget.questionsAnswered == false
? () {
setState(() {
if (widget.iscorrectAnswer3 == true) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Correct!'),
),
);
widget.score += 1;
} else {
disableButton();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text('Wrong Answer!'),
));
}
});
}
: null),
),
),
)
],
);
}
}
Main widget where I call this custom widget
class Quiz extends StatefulWidget {
Quiz({Key? key}) : super(key: key);
int score = 0;
#override
_QuizState createState() => _QuizState();
}
class _QuizState extends State<Quiz> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('CyberQuiz'),
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Questions(
'images/malware_quiz.jpeg',
'1. What is a malware?',
'Designed to damage computers, servers or any other devices',
"Used to get user's credentials",
"It's used to destroy networks",
'',
true,
false,
false,
false,
),
],
)));
}
}
As you suggest in your question, you could create a global variable and increment/decrease/reset that.
Basic example code:
import 'package:flutter/material.dart';
class Score {
static int score = 0;
}
class ScoreCounter extends StatefulWidget {
const ScoreCounter({Key? key}) : super(key: key);
#override
State<ScoreCounter> createState() => _ScoreCounterState();
}
class _ScoreCounterState extends State<ScoreCounter> {
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
setState(() {
Score.score++;
});
},
child: Text('increase score'),
),
),
Expanded(child: Text(Score.score.toString()))
],
);
}
}
Another option is to use the Provider package - link here which has an example
Provider Package
I have a small code for a shopping cart counter in my app, when running the app it does not update upon pressing the add or remove button (+ & - icons), although I assigned the functions for both of them, no errors are shown as to why this is happening...
This is the code for the counter:
import 'package:flutter/material.dart';
class CartCounter extends StatefulWidget {
#override
_CartCounterState createState() => _CartCounterState();
}
class _CartCounterState extends State<CartCounter> {
int numOfItems = 0;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
buildOutlineButton(
icon: Icons.remove,
press: () {
if (numOfItems > 0) {
setState(() {
numOfItems--;
});
}
},
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin / 2),
child: Text(
// if our item is less then 10 then it shows 01 02 like that
numOfItems.toString().padLeft(2, "0"),
style: Theme.of(context).textTheme.headline6,
),
),
buildOutlineButton(
icon: Icons.add,
press: () {
if (numOfItems < 10) {
setState(() {
numOfItems++;
});
}
}),
],
);
}
SizedBox buildOutlineButton(
{required IconData icon, required Function press}) {
return SizedBox(
width: 40,
height: 32,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
padding: EdgeInsets.zero,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(13.0)),
),
onPressed: press(),
child: Icon(icon),
),
);
}
}
And this is the code where I call the Cart Counter class, it also has a rating bar that works perfectly fine:
class CounterWithRateBar extends StatefulWidget {
#override
_CounterWithRateBarState createState() => _CounterWithRateBarState();
}
class _CounterWithRateBarState extends State<CounterWithRateBar> {
// const CounterWithRateBar({
// Key? key,
// }) : super(key: key);
late double _rating;
int _ratingBarMode = 1;
double _initialRating = 2.0;
IconData? _selectedIcon;
#override
void initState() {
super.initState();
_rating = _initialRating;
}
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CartCounter(),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children:
<Widget>[
SizedBox(
height: 10.0,
),
_ratingBar(_ratingBarMode),
SizedBox(height: 5.0),
Text(
'Rating: $_rating',
style: TextStyle(fontWeight: FontWeight.bold),
),
]
),
],
);
}
Widget _ratingBar(int mode) {
return RatingBar.builder(
initialRating: _initialRating,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
unratedColor: Colors.amber.withAlpha(50),
itemCount: 5,
itemSize: 25.0,
itemPadding: EdgeInsets.symmetric(horizontal: 2.0),
itemBuilder: (context, _) => Icon(
_selectedIcon ?? Icons.star,
color: Colors.amber,
),
onRatingUpdate: (rating) {
setState(() {
_rating = rating;
});
},
updateOnDrag: true,
);
}
}
You have small mistake in buildOutlineButtonDefinition
You immediately calling press function and not using is as callback;
From
onPressed: press(),
To
onPressed: () => press(),
Full definition would be
SizedBox buildOutlineButton(
{required IconData icon, required Function press}) {
return SizedBox(
width: 40,
height: 32,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
padding: EdgeInsets.zero,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(13.0)),
),
onPressed: () => press(),
child: Icon(icon),
),
);
}
Good Morning,
I'm trying to put a Carousel on the home page looking for Firebase data, but for some reason, the first time I load the application it appears the message below:
════════ Exception caught by widgets library ═════════════════════════════════════ ══════════════════
The following _CastError was thrown building DotsIndicator (animation: PageController # 734f9 (one client, offset 0.0), dirty, state: _AnimatedState # 636ca):
Null check operator used on a null value
and the screen looks like this:
After giving a hot reload the error continues to appear, but the image is loaded successfully, any tips of what I can do?
HomeManager:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provantagens_app/models/section.dart';
class HomeManager extends ChangeNotifier{
HomeManager({this.images}){
_loadSections();
images = images ?? [];
}
void addSection(Section section){
_editingSections.add(section);
notifyListeners();
}
final List<dynamic> _sections = [];
List<String> images;
List<dynamic> newImages;
List<dynamic> _editingSections = [];
bool editing = false;
bool loading = false;
int index, totalItems;
final Firestore firestore = Firestore.instance;
Future<void> _loadSections() async{
loading = true;
firestore.collection('home').snapshots().listen((snapshot){
_sections.clear();
for(final DocumentSnapshot document in snapshot.documents){
_sections.add( Section.fromDocument(document));
images = List<String>.from(document.data['images'] as List<dynamic>);
}
});
loading = false;
notifyListeners();
}
List<dynamic> get sections {
if(editing)
return _editingSections;
else
return _sections;
}
void enterEditing({Section section}){
editing = true;
_editingSections = _sections.map((s) => s.clone()).toList();
defineIndex(section: section);
notifyListeners();
}
void saveEditing() async{
bool valid = true;
for(final section in _editingSections){
if(!section.valid()) valid = false;
}
if(!valid) return;
loading = true;
notifyListeners();
for(final section in _editingSections){
await section.save();
}
for(final section in List.from(_sections)){
if(!_editingSections.any((s) => s.id == section.id)){
await section.delete();
}
}
loading = false;
editing = false;
notifyListeners();
}
void discardEditing(){
editing = false;
notifyListeners();
}
void removeSection(Section section){
_editingSections.remove(section);
notifyListeners();
}
void onMoveUp(Section section){
int index = _editingSections.indexOf(section);
if(index != 0) {
_editingSections.remove(section);
_editingSections.insert(index - 1, section);
index = _editingSections.indexOf(section);
}
notifyListeners();
}
HomeManager clone(){
return HomeManager(
images: List.from(images),
);
}
void onMoveDown(Section section){
index = _editingSections.indexOf(section);
totalItems = _editingSections.length;
if(index < totalItems - 1){
_editingSections.remove(section);
_editingSections.insert(index + 1, section);
index = _editingSections.indexOf(section);
}else{
}
notifyListeners();
}
void defineIndex({Section section}){
index = _editingSections.indexOf(section);
totalItems = _editingSections.length;
notifyListeners();
}
}
HomeScreen:
import 'package:carousel_pro/carousel_pro.dart';
import 'package:flutter/material.dart';
import 'package:provantagens_app/commom/custom_drawer.dart';
import 'package:provantagens_app/commom/custom_icons_icons.dart';
import 'package:provantagens_app/models/home_manager.dart';
import 'package:provantagens_app/models/section.dart';
import 'package:provantagens_app/screens/home/components/home_carousel.dart';
import 'package:provantagens_app/screens/home/components/menu_icon_tile.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
// ignore: must_be_immutable
class HomeScreen extends StatelessWidget {
HomeManager homeManager;
Section section;
List<Widget> get children => null;
String videoUrl = 'https://www.youtube.com/watch?v=VFnDo3JUzjs';
int index;
var _tapPosition;
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(colors: const [
Colors.white,
Colors.white,
], begin: Alignment.topCenter, end: Alignment.bottomCenter)),
child: Scaffold(
backgroundColor: Colors.transparent,
drawer: CustomDrawer(),
appBar: AppBar(
backgroundColor: Colors.transparent,
iconTheme: IconThemeData(color: Colors.black),
title: Text('Página inicial', style: TextStyle(color: Color.fromARGB(255, 30, 158, 8))),
centerTitle: true,
actions: <Widget>[
Divider(),
],
),
body: Consumer<HomeManager>(
builder: (_, homeManager, __){
return ListView(children: <Widget>[
AspectRatio(
aspectRatio: 1,
child:HomeCarousel(homeManager),
),
Column(
children: <Widget>[
Container(
height: 50,
),
Divider(
color: Colors.black,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Padding(
padding: const EdgeInsets.only(left:12.0),
child: MenuIconTile(title: 'Parceiros', iconData: Icons.apartment, page: 1,),
),
Padding(
padding: const EdgeInsets.only(left:7.0),
child: MenuIconTile(title: 'Beneficios', iconData: Icons.card_giftcard, page: 2,),
),
Padding(
padding: const EdgeInsets.only(right:3.0),
child: MenuIconTile(title: 'Suporte', iconData: Icons.help_outline, page: 6,),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
MenuIconTile(iconData: Icons.assignment,
title: 'Dados pessoais',
page: 3)
,
MenuIconTile(iconData: Icons.credit_card_outlined,
title: 'Meu cartão',
page: 4)
,
MenuIconTile(iconData: Icons.account_balance_wallet_outlined,
title: 'Pagamento',
page: 5,)
,
],
),
Divider(
color: Colors.black,
),
Container(
height: 50,
),
Consumer<HomeManager>(
builder: (_, sec, __){
return RaisedButton(
child: Text('Teste'),
onPressed: (){
Navigator.of(context)
.pushReplacementNamed('/teste',
arguments: sec);
},
);
},
),
Text('Saiba onde usar o seu', style: TextStyle(color: Colors.black, fontSize: 20),),
Text('Cartão Pró Vantagens', style: TextStyle(color: Color.fromARGB(255, 30, 158, 8), fontSize: 30),),
AspectRatio(
aspectRatio: 1,
child: Image.network(
'https://static.wixstatic.com/media/d170e1_80b5f6510f5841c19046f1ed5bca71e4~mv2.png/v1/fill/w_745,h_595,al_c,q_90,usm_0.66_1.00_0.01/Arte_Cart%C3%83%C2%B5es.webp',
fit: BoxFit.fill,
),
),
Divider(),
Container(
height: 150,
child: Row(
children: [
AspectRatio(
aspectRatio: 1,
child: Image.network(
'https://static.wixstatic.com/media/d170e1_486dd638987b4ef48d12a4bafee20e80~mv2.png/v1/fill/w_684,h_547,al_c,q_90,usm_0.66_1.00_0.01/Arte_Cart%C3%83%C2%B5es_2.webp',
fit: BoxFit.fill,
),
),
Padding(
padding: const EdgeInsets.only(left:20.0),
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: 'Adquira já o seu',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
TextSpan(
text: '\n\CARTÃO PRÓ VANTAGENS',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 30, 158, 8)),
),
]),
),
),
],
),
),
Divider(),
tableBeneficios(),
Divider(),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
'O cartão Pró-Vantagens é sediado na cidade de Hortolândia/SP e já está no mercado há mais de 3 anos. Somos um time de profissionais apaixonados por gestão de benefícios e empenhados em gerar o máximo de valor para os conveniados.'),
FlatButton(
onPressed: () {
launch(
'https://www.youtube.com/watch?v=VFnDo3JUzjs');
},
child: Text('SAIBA MAIS')),
],
),
),
Container(
color: Color.fromARGB(255, 105, 190, 90),
child: Column(
children: <Widget>[
Row(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'© 2020 todos os direitos reservados a Cartão Pró Vantagens.',
style: TextStyle(fontSize: 10),
),
)
],
),
Divider(),
Row(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'Rua Luís Camilo de Camargo, 175 -\n\Centro, Hortolândia (piso superior)',
style: TextStyle(fontSize: 10),
),
),
Padding(
padding: const EdgeInsets.only(left: 16),
child: IconButton(
icon: Icon(CustomIcons.facebook),
color: Colors.black,
onPressed: () {
launch(
'https://www.facebook.com/provantagens/');
},
),
),
Padding(
padding: const EdgeInsets.only(left: 16),
child: IconButton(
icon: Icon(CustomIcons.instagram),
color: Colors.black,
onPressed: () {
launch(
'https://www.instagram.com/cartaoprovantagens/');
},
),
),
],
),
],
),
)
],
),
]);
},
)
),
);
}
tableBeneficios() {
return Table(
defaultColumnWidth: FlexColumnWidth(120.0),
border: TableBorder(
horizontalInside: BorderSide(
color: Colors.black,
style: BorderStyle.solid,
width: 1.0,
),
verticalInside: BorderSide(
color: Colors.black,
style: BorderStyle.solid,
width: 1.0,
),
),
children: [
_criarTituloTable(",Plus, Premium"),
_criarLinhaTable("Seguro de vida\n\(Morte Acidental),X,X"),
_criarLinhaTable("Seguro de Vida\n\(Qualquer natureza),,X"),
_criarLinhaTable("Invalidez Total e Parcial,X,X"),
_criarLinhaTable("Assistência Residencial,X,X"),
_criarLinhaTable("Assistência Funeral,X,X"),
_criarLinhaTable("Assistência Pet,X,X"),
_criarLinhaTable("Assistência Natalidade,X,X"),
_criarLinhaTable("Assistência Eletroassist,X,X"),
_criarLinhaTable("Assistência Alimentação,X,X"),
_criarLinhaTable("Descontos em Parceiros,X,X"),
],
);
}
_criarLinhaTable(String listaNomes) {
return TableRow(
children: listaNomes.split(',').map((name) {
return Container(
alignment: Alignment.center,
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: name != "X" ? '' : 'X',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
TextSpan(
text: name != 'X' ? name : '',
style: TextStyle(
fontSize: 10.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 30, 158, 8)),
),
]),
),
padding: EdgeInsets.all(8.0),
);
}).toList(),
);
}
_criarTituloTable(String listaNomes) {
return TableRow(
children: listaNomes.split(',').map((name) {
return Container(
alignment: Alignment.center,
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: name == "" ? '' : 'Plano ',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
TextSpan(
text: name,
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 30, 158, 8)),
),
]),
),
padding: EdgeInsets.all(8.0),
);
}).toList(),
);
}
void _storePosition(TapDownDetails details) {
_tapPosition = details.globalPosition;
}
}
I forked the library to create a custom carousel for my company's project, and since we updated flutter to 2.x we had the same problem.
To fix this just update boolean expressions like
if(carouselState.pageController.position.minScrollExtent == null ||
carouselState.pageController.position.maxScrollExtent == null){ ... }
to
if(!carouselState.pageController.position.hasContentDimensions){ ... }
Here is flutter's github reference.
This worked for me
So I edited scrollposition.dart package
from line 133
#override
//double get minScrollExtent => _minScrollExtent!;
// double? _minScrollExtent;
double get minScrollExtent {
if (_minScrollExtent == null) {
_minScrollExtent = 0.0;
}
return double.parse(_minScrollExtent.toString());
}
double? _minScrollExtent;
#override
// double get maxScrollExtent => _maxScrollExtent!;
// double? _maxScrollExtent;
double get maxScrollExtent {
if (_maxScrollExtent == null) {
_maxScrollExtent = 0.0;
}
return double.parse(_maxScrollExtent.toString());
}
double? _maxScrollExtent;
Just upgrade to ^3.0.0 Check here https://pub.dev/packages/carousel_slider
I faced the same issue.
This is how I solved it
class PlansPage extends StatefulWidget {
const PlansPage({Key? key}) : super(key: key);
#override
State<PlansPage> createState() => _PlansPageState();
}
class _PlansPageState extends State<PlansPage> {
int _currentPage = 1;
late CarouselController carouselController;
#override
void initState() {
super.initState();
carouselController = CarouselController();
}
}
Then put initialization the carouselController inside the initState method I was able to use the methods jumpToPage(_currentPage ) and animateToPage(_currentPage) etc.
I use animateToPage inside GestureDetector in onTap.
onTap: () {
setState(() {
_currentPage = pageIndex;
});
carouselController.animateToPage(_currentPage);
},
I apologize in advance if this is inappropriate.
I solved the similar problem as follows. You can take advantage of the Boolean variable. I hope, help you.
child: !loading ? HomeCarousel(homeManager) : Center(child:ProgressIndicator()),
or
child: isLoading ? HomeCarousel(homeManager) : SplashScreen(),
class SplashScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Loading...')
),
);
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:greycell_app/src/commons/actions/dialog_handler.dart';
import 'package:greycell_app/src/commons/themes/textstyle.dart';
import 'package:greycell_app/src/commons/widgets/error_data.dart';
import 'package:greycell_app/src/manager/main_model.dart';
import 'package:greycell_app/src/models/payment/due_detail.dart';
import 'package:greycell_app/src/models/payment/payable_fee.dart';
import 'package:greycell_app/src/models/response/response.dart';
import 'package:greycell_app/src/models/response/success.dart';
import 'package:greycell_app/src/views/accountViews/account_header.dart';
import 'package:greycell_app/src/views/accountViews/pay_option.dart';
import 'package:greycell_app/src/views/paymentViews/payable_tile.dart';
import 'package:greycell_app/src/views/paymentViews/payment_confirmation_screen.dart';
import 'package:greycell_app/src/views/paymentViews/payment_edit_field_view.dart';
import 'package:scoped_model/scoped_model.dart';
class PaymentBodyView extends StatefulWidget {
final DueDetail dueDetail;
final MainModel model;
//
const PaymentBodyView({this.dueDetail, this.model});
#override
_MyPaymentScreenState createState() => _MyPaymentScreenState();
}
class _MyPaymentScreenState extends State<PaymentBodyView> {
final TextEditingController _paymentEditController = TextEditingController();
final TextEditingController _paymentSearchController =
TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final double minValue = 8.0;
DueDetail _dueDetail;
double _totalFeeAmount = 0.0;
/// Is user is Scrolling
bool isScrollDown = false;
ScrollController _scrollController;
// Current Index
int _currentIndex = -999999;
void setUp() {
if (_dueDetail.getPayAmtFrom == 'FA') {
// There will be one custom payable fee in the list: for more info check Account Service for FA
widget.model.addPayableFee(_dueDetail.payableFeeDetails.first);
}
}
void _onCreated() async {
_dueDetail = widget.dueDetail;
if (_dueDetail == null) {
// Make Api Call and Get Data
final ResponseMania _result = await widget.model.getAccountDueDetail();
if (_result is Success) {
_dueDetail = _result.success;
setUp();
_calculateAmount();
}
} else {
// You have transaction data
setUp();
_calculateAmount();
}
}
void _calculateAmount() {
if (_dueDetail != null && _dueDetail.payableFeeDetails != null) {
_dueDetail.payableFeeDetails.forEach((PayableFee fee) {
_totalFeeAmount += fee.feeAmount;
});
}
setState(() {});
}
void _onPayableTap(int index) {
if (!mounted) return;
setState(() {
if (_currentIndex == index) {
_currentIndex = -99999;
}
else {
_currentIndex = index;
}
});
}
void _onAddPayableFee(int index, PayableFee selectedFee) {
widget.model.addPayableFee(selectedFee);
_showSnackBar("Added to the payment");
setState(() {
_currentIndex = -99999;
});
}
void _onEditPayableFee(int index, PayableFee selectedFee) async {
_paymentEditController.text = selectedFee.feeAmount.toString();
DialogHandler.onCustomAlertDialog(
title: "Edit amount",
context: context,
content: PaymentEditTextFiled(
context: context,
key: _formKey,
fee: selectedFee,
paymentEditController: _paymentEditController,
).build(),
onSubmit: () {
if (_formKey.currentState.validate()) {
selectedFee.netPayAbleAmount =
double.parse(_paymentEditController.text);
widget.model.editPayableAmount(index, selectedFee);
Navigator.of(context).pop();
_showSnackBar("Updated and added to the payment");
}
});
}
void _onRemovePayableFee(int index, PayableFee selectedFee) {
print("remove Called");
widget.model.removePayableFee(selectedFee);
_showSnackBar("Successfully removed");
setState(() {
_currentIndex = -99999;
});
}
void _onProceedToPay() {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (_) => PaymentConfirmationScreen(
model: widget.model,
dueDetail: _dueDetail,
totalFeeAmount: _totalFeeAmount,
totalPayAbleAmount: widget.model.totalPayableAmount,
payableFees: widget.model.selectedPayableFees
// payableFees: <PayableFee>[_dueDetail.payableFeeDetails[0]],
)))
.then((value) {});
}
void _reset() {
widget.model.clearSelectedPayable();
}
#override
void dispose() {
_scrollController.dispose();
_reset();
super.dispose();
}
#override
void initState() {
super.initState();
_onCreated();
_scrollController = ScrollController(initialScrollOffset: 0.0);
}
bool get isNotDueFound =>
_dueDetail.payableFeeDetails == null ||
_dueDetail.payableFeeDetails.length == 0;
void onAllSelectChanged(bool value) {}
void _showSnackBar(String msg) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
"$msg",
style: CustomTextStyle(context).caption.apply(color: Colors.white),
),
backgroundColor: Colors.green[400],
));
}
Widget _buildPaymentButton() {
return Container(
width: MediaQuery.of(context).size.width,
height: 50.0,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.blue, Theme.of(context).primaryColor])),
child: MaterialButton(
padding: EdgeInsets.all(15.0),
onPressed: _onProceedToPay,
child: Text(
"Proceed to pay",
style: CustomTextStyle(context)
.subtitle1
.apply(color: Colors.white, fontWeightDelta: 1),
),
textColor: Colors.white,
),
);
}
Widget _buildTotalAmount() {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("Total fee amount"),
Text(
"₹${_totalFeeAmount}",
style: CustomTextStyle(context)
.subtitle1
.apply(fontWeightDelta: 1),
)
],
),
SizedBox(
height: 12.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("Net payable amount"),
ScopedModelDescendant(builder: (_, __, MainModel model) {
return Text(
"₹${model.totalPayableAmount}",
style: CustomTextStyle(context)
.subtitle1
.apply(fontWeightDelta: 1),
);
})
],
),
],
),
);
}
Widget _buildFinalAmount() {
return ScopedModelDescendant(builder: (_, __, MainModel model) {
return Container(
padding: EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Final Payable Amount",
style: CustomTextStyle(context).subtitle2,
),
Flexible(
child: Text(
"₹${model.totalPayableAmount}",
style: CustomTextStyle(context).headline6,
),
),
],
),
);
});
}
Widget _buildFAbody() {
final PayableFee _fee = _dueDetail.payableFeeDetails.first;
return Container(
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
PayableTile(
isEditable: false,
isSelected: false,
payableFee: _fee,
),
_dueDetail.getPolicyValue != "P"
? Container()
: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Text(
"Partially Pay",
style: CustomTextStyle(context).subtitle2,
),
),
MaterialButton(
onPressed: () => _onEditPayableFee(0, _fee),
child: Text("Change"),
padding: EdgeInsets.symmetric(vertical: 15.0),
)
],
),
Divider(),
_buildFinalAmount(),
SizedBox(
height: 20.0,
),
Padding(
padding: const EdgeInsets.all(16.0),
child: _buildPaymentButton(),
),
],
),
),
);
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.grey[50],
child: _dueDetail == null
? Center(
child: CircularProgressIndicator(),
)
: Column(
children: <Widget>[
Expanded(
child: Container(
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
// PaymentSearchFilter(),
MyAccountInfoHeader(
dueDetail: _dueDetail,
),
MyOnlinePayOption(
dueDetail: _dueDetail,
),
isNotDueFound
? MyErrorData(
errorMsg: "No dues found",
subtitle: "No payable fees available",
)
: _dueDetail.getPayAmtFrom == 'FA'
? _buildFAbody()
: ListView.builder(
controller: _scrollController,
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount:
_dueDetail.payableFeeDetails.length.compareTo(0),
itemBuilder:
(BuildContext context, int index) {
final PayableFee _fee =
_dueDetail.payableFeeDetails[index];
return PayableTile(
payableFee: _fee,
isEditable:
_dueDetail.getPolicyValue == "P",
onChanged: () {
_onPayableTap(index);
},
isSelected: _currentIndex == index,
onBottomAction: (String action) {
if (action == 'EDIT')
_onEditPayableFee(index, _fee);
else if (action == 'DELETE')
_onRemovePayableFee(index, _fee);
else
_onAddPayableFee(index, _fee);
},
);
}),
],
),
),
),
),
isNotDueFound || _dueDetail.getPayAmtFrom == 'FA'
? Container()
: Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.blue[50],
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12.0))),
// padding: EdgeInsets.symmetric(horizontal: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_buildTotalAmount(),
_buildPaymentButton(),
],
),
),
)
],
),
);
}
}
RangeError (index): Invalid value: Valid value range is empty: 0
This error is coming when I try to press a button to open this page. How to fix it please help. It's taking too much of my time... Please help me out solving this.
Most probably it is a ListView problem or something... Check it out, please. I am fetching data from
API here on the page & doing some calculations.