rajap
rajap

Reputation: 77

Flutter flashes screen light blue when using setState()

OK, I've searched for a long time, and to no avail. This problem seems to be an issue with the build cache, but I can find no resources on clearing the build cache, nor any resources on how to fix this specific issue.

My code is as follows:

part of finance_app;

class InvestmentDetail extends StatefulWidget {
  final String userEmail;
  final String userName;
  final String profilePic;
  final String providerID;
  final String uid;
  InvestmentDetail(
      {@required this.userEmail,
      @required this.userName,
      @required this.profilePic,
      @required this.providerID,
      @required this.uid});
  @override
  _InvestmentDetailState createState() => _InvestmentDetailState();
}

final FirebaseAuth _auth = FirebaseAuth.instance;

class _InvestmentDetailState extends State<InvestmentDetail>
    with SingleTickerProviderStateMixin {
  bool firstRun = true;
  bool showMoney = true;
  bool readyToShowChart = false;
  var refreshkey = GlobalKey<RefreshIndicatorState>();
  LineChart chart;
  bool isTapped = false;
  Future<String> displayName() async {
    FirebaseUser _user = await FirebaseAuth.instance.currentUser();
    return _user.displayName;
  }

// various other functions go here

  void createLine2() {
    print("working");
    Firestore.instance
        .collection("user/" + widget.userEmail + "/investmentHistory")
        .snapshots()
        .listen(
          (data) => {
            print(data),
            line1 = {},
            data.documents.forEach(
              (doc) => {
                print(doc["percentage"]),
                line1[DateTime.fromMillisecondsSinceEpoch(
                    int.parse(doc.documentID).round())] = doc["percentage"],
              },
            ),
            chart = !f.format(percentageChangeTotal).contains("-")
                ? LineChart.fromDateTimeMaps(
                    [line1], [Colors.red], ['%'],
                  )
                : LineChart.fromDateTimeMaps(
                    [line1], [Colors.green], ['%'],
                  ),
          },
        );
  }
  @override
  void dispose() {
    super.dispose();
  }

  @override
  void initState() {
    createLine2();
    super.initState();
  }


  
  @override
  Widget build(BuildContext context) {
    createLine2();
    return WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        body: SafeArea(
          child: Column(
            children: <Widget>[
              Expanded(
                child: StreamBuilder<QuerySnapshot>(
                  stream: Firestore.instance
                      .collection(
                          'user/' + widget.userEmail + '/positionLabels')
                      .orderBy("Date", descending: true)
                      .orderBy("Time", descending: true)
                      .snapshots(),
                  builder: (BuildContext context,
                      AsyncSnapshot<QuerySnapshot> snapshot) {
                    if (snapshot.hasError) {
                      return new Text('Error: ${snapshot.error}');
                    }
                    if (!snapshot.hasData) {
                      return Padding(
                        padding: const EdgeInsets.all(50.0),
                        child: Center(
                          child: Text(
                            "Add your first transaction!\n\nTap your profile picture in the top right to add your first order",
                            style: TextStyle(color: Colors.white),
                            textAlign: TextAlign.center,
                          ),
                        ),
                      );
                    } else {
                      switch (snapshot.connectionState) {
                        case ConnectionState.none:
                          print("ConnectionState: NONE");
                          return Text(
                            'Select',
                            style: TextStyle(color: Colors.white),
                          );
                        case ConnectionState.waiting:
                          print("ConnectionState: WAITING");
                          return LinearProgressIndicator();
                        case ConnectionState.done:
                          print("ConnectionState: DONE");
                          return Text(
                            '\$${snapshot.data} (closed)',
                            style: TextStyle(color: Colors.white),
                          );
                        default:
                          return Column(
                            children: <Widget>[
                              SearchBar(
                                  widget: widget,
                                  nodeOne: nodeOne,
                                  controller: controller),
                              GestureDetector(
                                onTap: () {
                                  setState(() {
                                    readyToShowChart = true;
                                  });
                                },
                                child: Column(
                                  children: <Widget>[
                                    Container(
                                      padding: EdgeInsets.only(
                                          top: 20,
                                          right: 10,
                                          left: 10,
                                          bottom: 5),
                                      height: 200,
                                      width: MediaQuery.of(context).size.width,
                                      child: AnimatedOpacity(
                                        duration: Duration(seconds: 2),
                                        opacity: readyToShowChart ? 1 : 0,
                                        child: AnimatedLineChart(
                                          chart,
                                          key: UniqueKey(),
                                        ),
                                      ),
                                    ),
                                    TotalPositionsWidget(
                                        f.format(
                                            getTotalMoneySpent(snapshot.data)),
                                        getTotalAccountValue(snapshot.data)),
                                    PositionsChangeWidget(
                                        workWithNumbers(snapshot.data),
                                        f.format(percentageChangeTotal)),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: RefreshIndicator(
                                  color: Colors.white,
                                  onRefresh: () => refreshMain(snapshot.data),
                                  key: refreshkey,
                                  child: ListView(
                                    children: snapshot.data.documents.map(
                                      (DocumentSnapshot document) {
                                        return new AnimatedOpacity(
                                          opacity: 1.0,
                                          duration:
                                              Duration(milliseconds: 1000),
                                          child: StockListTile(
                                              document, widget.userEmail),
                                        );
                                      },
                                    ).toList(),
                                  ),
                                ),
                              ),
                            ],
                          );
                      }
                    }
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

To simplify: I have a StreamBuilder that has a column as its child. The Column contains:

When I tap on the Text widget and trigger "setState", the screen flashes a light blue before executing the command:

tapping the Text widget three times

It looks like Flutter is rebuilding the entire layout.

A smaller side problem (though not anywhere near as important as the flashing blue screen) is that AnimatedOpacity and AnimatedCrossFade never actually animate in this widget, but do in others (SearchBar as an example)

I've seen this example, and it is similar to what I'm experiencing, but I'm not dealing with images here, so I don't know where to go.

I've also tried Dart DevTools, and all that I've been able to get is that (using the bottom up view in the timeline) it is stuck in a "performLayout --> layout --> performLayout --> layout" loop

Could someone please point me in the right direction?

Upvotes: 3

Views: 4535

Answers (1)

rajap
rajap

Reputation: 77

For those who run into this problem in the future, the answer is as follows:

Flutter rebuild the entire stateful widget on "setState", so the blue flash is caused by re-building the entire widget - basically the entire app. To remove the flash, transition as many widgets as possible to Stateless widgets, so that on rebuild, Flutter doesn't have to rebuild every single widget over again.

Upvotes: 3

Related Questions