Generating a view asynchronously with Flutter

412 views
Skip to first unread message

Dev Connect

unread,
Feb 28, 2020, 2:49:05 AM2/28/20
to Flutter Development (flutter-dev)
Hi the code below generates a view based on arrays that are taken from a json rest. Then the code must be inserted from the array inside the view. However, when I start executing the code I have a series of errors that are reported below. The problem is that when the function ​inizializzaValori​() is called; the code makes an asynchronous call with Cantiere.ricerca(..) this function makes a rest call that returns inside an array. Basically the problem lies in the fact that to generate the view, this view needs to make a rest call.


Error:
Failed assertion: line 1651 pos 12: '!_debugDoingThisLayout': is not true.
flutter
: Another exception was thrown: NoSuchMethodError: The getter 'length' was called on null.
flutter
: Another exception was thrown: Each child must be laid out exactly once.
flutter
: Another exception was thrown: NoSuchMethodError: The getter 'length' was called on null.
flutter
: Another exception was thrown: Each child must be laid out exactly once.
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: Cannot hit test a render box that has never been laid out.
The hitTest() method was called on this RenderBox: RenderStack#8e720 NEEDS-LAYOUT NEEDS-PAINT:
  creator
: Stack FutureBuilder<bool> _BodyBuilder MediaQuery LayoutId-[<_ScaffoldSlot.body>] CustomMultiChildLayout AnimatedBuilder DefaultTextStyle AnimatedDefaultTextStyle _InkFeatures-[GlobalKey#19263 ink renderer] ← NotificationListener<LayoutChangedNotification> ← PhysicalModel ← ⋯
  parentData
: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.body
  constraints
: MISSING
  size
: MISSING
  alignment
: AlignmentDirectional.topStart
  textDirection
: ltr
  fit
: loose
  overflow
: clip
Unfortunately, this object's geometry is not known at this time, probably because it has never been laid out. This means it cannot be accurately hit-tested.
If you are trying to perform a hit test during the layout phase itself, make sure you only hit test nodes that have complet<…>


scheda_cantieri_view.dart:
import 'package:flutter/material.dart' ;
import 'package:MyApp/Model/Cantiere.dart';
import '../Home_theme.dart';
import 'package:MyApp/Utils/Style/color.dart';


//Classe che rappresenta la scheda di un cantiere
class SchedaCantieriView extends StatelessWidget {
 
final AnimationController animationController;
 
final Animation animation;
 
//Oggetto che rappresenta il cantiere
 
final Cantiere ctemp;

 
//Costruttore
 
const SchedaCantieriView({Key key, this.animationController, this.animation, this.ctemp})
     
: super(key: key);

 
@override
 
Widget build(BuildContext context) {
   
return AnimatedBuilder(
      animation
: animationController,
      builder
: (BuildContext context, Widget child) {
       
return FadeTransition(
          opacity
: animation,
          child
: new Transform(
            transform
: new Matrix4.translationValues(
               
0.0, 30 * (1.0 - animation.value), 0.0),
            child
: Padding(
              padding
: const EdgeInsets.only(
                  left
: 24, right: 24, top: 16, bottom: 18),
              child
: Container(
                decoration
: BoxDecoration(
                  gradient
: LinearGradient(colors: [
                   
FintnessAppTheme.nearlyDarkBlue,
                   
HexColor("#6F56E8")
                 
], begin: Alignment.topLeft, end: Alignment.bottomRight),
                  borderRadius
: BorderRadius.only(
                      topLeft
: Radius.circular(8.0),
                      bottomLeft
: Radius.circular(8.0),
                      bottomRight
: Radius.circular(8.0),
                      topRight
: Radius.circular(68.0)),
                  boxShadow
: <BoxShadow>[
                   
BoxShadow(
                        color
: FintnessAppTheme.grey.withOpacity(0.6),
                        offset
: Offset(1.1, 1.1),
                        blurRadius
: 10.0),
                 
],
               
),
                child
: Padding(
                  padding
: const EdgeInsets.all(16.0),
                  child
: Column(
                    mainAxisAlignment
: MainAxisAlignment.center,
                    crossAxisAlignment
: CrossAxisAlignment.start,
                    children
: <Widget>[
                     
Text(
                       
'',
                        textAlign
: TextAlign.left,
                        style
: TextStyle(
                          fontFamily
: FintnessAppTheme.fontName,
                          fontWeight
: FontWeight.normal,
                          fontSize
: 14,
                          letterSpacing
: 0.0,
                          color
: FintnessAppTheme.white,
                       
),
                     
),
                     
Padding(
                        padding
: const EdgeInsets.only(top: 8.0),
                        child
: Text(
                         
'Cantiere: '+ctemp.getNomeCantiere().toString()+' \n\nCliente: '+ctemp.getRagioneSociale()+'',
                          textAlign
: TextAlign.left,
                          style
: TextStyle(
                            fontFamily
: FintnessAppTheme.fontName,
                            fontWeight
: FontWeight.normal,
                            fontSize
: 20,
                            letterSpacing
: 0.0,
                            color
: FintnessAppTheme.white,
                         
),
                       
),
                     
),
                     
SizedBox(
                        height
: 32,
                     
),
                     
Padding(
                        padding
: const EdgeInsets.only(right: 4),
                        child
: Row(
                          crossAxisAlignment
: CrossAxisAlignment.end,
                          mainAxisAlignment
: MainAxisAlignment.center,
                          children
: <Widget>[
                           
Padding(
                              padding
: const EdgeInsets.only(left: 4),
                              child
: Icon(
                               
Icons.timer,
                                color
: FintnessAppTheme.white,
                                size
: 16,
                             
),
                           
),
                           
Padding(
                              padding
: const EdgeInsets.only(left: 4.0),
                              child
: Text(
                               
''+ctemp.getDataCreazione(),
                                textAlign
: TextAlign.center,
                                style
: TextStyle(
                                  fontFamily
: FintnessAppTheme.fontName,
                                  fontWeight
: FontWeight.w500,
                                  fontSize
: 14,
                                  letterSpacing
: 0.0,
                                  color
: FintnessAppTheme.white,
                               
),
                             
),
                           
),
                           
Expanded(
                              child
: SizedBox(),
                           
),
                           
Container(
                              decoration
: BoxDecoration(
                                color
: FintnessAppTheme.nearlyWhite,
                                shape
: BoxShape.circle,
                                boxShadow
: <BoxShadow>[
                                 
BoxShadow(
                                      color
: FintnessAppTheme.nearlyBlack
                                         
.withOpacity(0.4),
                                      offset
: Offset(8.0, 8.0),
                                      blurRadius
: 8.0),
                               
],
                             
),

                             
//Bottone che permette l'accesso al cantiere
                              child
: Padding(
                                padding
: const EdgeInsets.all(0.0),
                                child
: Icon(
                                 
Icons.arrow_right,
                                  color
: HexColor("#6F56E8"),
                                  size
: 44,
                               
),
                             
),
                           
)
                         
],
                       
),
                     
)
                   
],
                 
),
               
),
             
),
           
),
         
),
       
);
     
},
   
);
 
}
}


TrainingScreenState.dart
import 'dart:async';


import 'package:MyApp/Controller/Cantiere.dart';
import 'package:MyApp/Model/Utente.dart';
import 'package:MyApp/View/Cantieri/scheda_cantiere_view.dart'
   
show SchedaCantieriView;
import 'package:flutter/material.dart';
import 'package:MyApp/Model/Cantiere.dart';
import 'package:MyApp/utils/support.dart';
import '../Home_theme.dart';

//Variabile che rappresenta l'utente all'interno della view
Utente utemp;
//Questa map rappresenta i cantieri ricercati
List<Cantiere> cantieriricercati;
//La funzione di inizializzazione esegue l'init di tutti i valori che
//verranno utilizzati nella view
Future<void> inizializzaValori() async {
 
//Estrapolo i valori per inizializzare l'utente
 
var email = await Storage.leggi("Email");
 
var password = await Storage.leggi("Password");
 
var idutente = int.parse(await Storage.leggi("IdUtente"));
 
//Inizializzo l'utente
  utemp
= new Utente.init(idutente, email, password);
 
//Inizializzo i cantieri all'avvio della form
  cantieriricercati
= await Cantiere.ricerca(utemp, 0, "", "", false);
 
//Stampa dei valori dei cantieri ricercati
 
for (int i = 0; i < cantieriricercati.length; i++) {
   
print
("Cantieri ricercati -- Nome Cantiere:  " +
        cantieriricercati
[i].getNomeCantiere());
 
}
}

class TrainingScreen extends StatefulWidget {
 
const TrainingScreen({Key key, this.animationController}) : super(key: key);

 
final AnimationController animationController;
 
@override
  _TrainingScreenState createState
() => _TrainingScreenState();
}

class _TrainingScreenState extends State<TrainingScreen>
   
with
TickerProviderStateMixin {
 
Animation<double> topBarAnimation;

 
List<Widget> listViews = <Widget>[];
 
final ScrollController scrollController = ScrollController();
 
double topBarOpacity = 0.0;

 
@override
 
void initState() {
   
//Funzione che inizializza i valori
    inizializzaValori
();

    topBarAnimation
= Tween<double>(begin: 0.0, end: 1.0).animate(
       
CurvedAnimation(
            parent
: widget.animationController,
            curve
: Interval(0, 0.5, curve: Curves.fastOutSlowIn)));
    addAllListData
();

    scrollController
.addListener(() {
     
if (scrollController.offset >= 24) {
       
if (topBarOpacity != 1.0) {
          setState
(() {
            topBarOpacity
= 1.0;
         
});
       
}
     
} else if (scrollController.offset <= 24 &&
          scrollController
.offset >= 0) {
       
if (topBarOpacity != scrollController.offset / 24) {
          setState
(() {
            topBarOpacity
= scrollController.offset / 24;
         
});
       
}
     
} else if (scrollController.offset <= 0) {
       
if (topBarOpacity != 0.0) {
          setState
(() {
            topBarOpacity
= 0.0;
         
});
       
}
     
}
   
});
   
super.initState();
 
}

 
void addAllListData() {
   
const int count = 5;

    listViews
.add(
     
new TextFormField(
        decoration
: new InputDecoration(
          labelText
: "Ricerca Cantieri",
          fillColor
: Colors.white,
          border
: new OutlineInputBorder(
            borderRadius
: new BorderRadius.circular(25.0),
            borderSide
: new BorderSide(),
         
),
         
//fillColor: Colors.green
       
),
        validator
: (val) {
         
if (val.length == 0) {
           
return "Il campo non può essere vuoto";
         
} else {
           
return null;
         
}
       
},
        keyboardType
: TextInputType.emailAddress,
        style
: new TextStyle(
          fontFamily
: "WorkSansSemiBold",
       
),
     
),
   
);

//Aggiunta alla list della view corrispondente al cantiere

    listViews
.add(
     
SchedaCantieriView(
        animation
: Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(
            parent
: widget.animationController,
            curve
:
               
Interval((1 / count) * 2, 1.0, curve: Curves.fastOutSlowIn))),
        animationController
: widget.animationController,
     
),
   
);


     
//Eseguo la ricerca dei cantieri
     
for (int i = 0; i < cantieriricercati.length; i++)
     
{
       
//Aggiunta alla list della view corrispondente al cantiere
        listViews
.add(
         
SchedaCantieriView(
            animation
: Tween<double>(begin: 0.0, end: 1.0).animate(
               
CurvedAnimation(
                    parent
: widget.animationController,
                    curve
: Interval((1 / count) * 2, 1.0,
                        curve
: Curves.fastOutSlowIn))),
            animationController
: widget.animationController,
            ctemp
: cantieriricercati[i],
         
),
       
);
     
}

 
}

 
Future<bool> getData() async {
   
await Future<dynamic>.delayed(const Duration(milliseconds: 50));
   
return true;
 
}

 
@override
 
Widget build(BuildContext context) {
   
return Container(
      color
: FintnessAppTheme.background,
      child
: Scaffold(
        backgroundColor
: Colors.transparent,
        body
: Stack(
          children
: <Widget>[
            getMainListViewUI
(),
            getAppBarUI
(),
           
SizedBox(
              height
: MediaQuery.of(context).padding.bottom,
           
)
         
],
       
),
     
),
   
);
 
}

 
Widget getMainListViewUI() {
   
return FutureBuilder<bool>(
      future
: getData(),
      builder
: (BuildContext context, AsyncSnapshot<bool> snapshot) {
       
if (!snapshot.hasData) {
         
return const SizedBox();
       
} else {
         
return ListView.builder(
            controller
: scrollController,
            padding
: EdgeInsets.only(
              top
: AppBar().preferredSize.height +
                 
MediaQuery.of(context).padding.top +
                 
24,
              bottom
: 62 + MediaQuery.of(context).padding.bottom,
           
),
            itemCount
: listViews.length,
            scrollDirection
: Axis.vertical,
            itemBuilder
: (BuildContext context, int index) {
              widget
.animationController.forward();
             
return listViews[index];
           
},
         
);
       
}
     
},
   
);
 
}

 
Widget getAppBarUI() {
   
return Column(
      children
: <Widget>[
       
AnimatedBuilder(
          animation
: widget.animationController,
          builder
: (BuildContext context, Widget child) {
           
return FadeTransition(
              opacity
: topBarAnimation,
              child
: Transform(
                transform
: Matrix4.translationValues(
                   
0.0, 30 * (1.0 - topBarAnimation.value), 0.0),
                child
: Container(
                  decoration
: BoxDecoration(
                    color
: FintnessAppTheme.white.withOpacity(topBarOpacity),
                    borderRadius
: const BorderRadius.only(
                      bottomLeft
: Radius.circular(32.0),
                   
),
                    boxShadow
: <BoxShadow>[
                     
BoxShadow(
                          color
: FintnessAppTheme.grey
                             
.withOpacity(0.4 * topBarOpacity),
                          offset
: const Offset(1.1, 1.1),
                          blurRadius
: 10.0),
                   
],
                 
),
                  child
: Column(
                    children
: <Widget>[
                     
SizedBox(
                        height
: MediaQuery.of(context).padding.top,
                     
),
                     
Padding(
                        padding
: EdgeInsets.only(
                            left
: 16,
                            right
: 16,
                            top
: 16 - 8.0 * topBarOpacity,
                            bottom
: 12 - 8.0 * topBarOpacity),
                        child
: Row(
                          mainAxisAlignment
: MainAxisAlignment.center,
                          children
: <Widget>[
                           
Expanded(
                              child
: Padding(
                                padding
: const EdgeInsets.all(8.0),
                                child
: Text(
                                 
'Cantieri',
                                  textAlign
: TextAlign.left,
                                  style
: TextStyle(
                                    fontFamily
: FintnessAppTheme.fontName,
                                    fontWeight
: FontWeight.w700,
                                    fontSize
: 22 + 6 - 6 * topBarOpacity,
                                    letterSpacing
: 1.2,
                                    color
: FintnessAppTheme.darkerText,
                                 
),
                               
),
                             
),
                           
),

                           
/*SizedBox(
                              height: 38,
                              width: 38,
                              child: InkWell(
                                highlightColor: Colors.transparent,
                                borderRadius: const BorderRadius.all(
                                    Radius.circular(32.0)),
                                onTap: () {},
                                child: Center(
                                  child: Icon(
                                    Icons.keyboard_arrow_right,
                                    color: FintnessAppTheme.grey,
                                  ),
                                ),
                              ),
                            ),*/

                         
],
                       
),
                     
)
                   
],
                 
),
               
),
             
),
           
);
         
},
       
)
     
],
   
);
 
}
}



Dev Connect

unread,
Feb 28, 2020, 3:36:40 AM2/28/20
to Flutter Development (flutter-dev)
I published the code with the flutter builder but always the same error.


        body
: FutureBuilder(
          future
: inizializzaValori(),
          builder
: (BuildContext context, AsyncSnapshot snapshot) {

Hugo van Galen

unread,
Feb 28, 2020, 4:13:50 AM2/28/20
to Dev Connect, Flutter Development (flutter-dev)
The variable cantieriricercati is accessed before the call to inizializzaValori() is made, so that's where the error comes from.

There are other issues with your code, I suggest you to read https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html on how to properly use the FutureBuilder,

Hope this helps.

--
You received this message because you are subscribed to the Google Groups "Flutter Development (flutter-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/flutter-dev/d0f6a728-2de2-4ced-942d-e0aec71610d4%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages