简体   繁体   中英

Flutter stream builder doesn't update Widget

I'm creating a calendar screen by using TableCalender and Cloud firestore.

I want to set _buildEventList() after assigning a value to selectedEvent at the place where selectedEvent is set, but because _buildEventList() is called first, it will be empty. But, after i set the value I'm calling setState(){} . Why the screen won't be updated?

final _firestore = Firestore.instance;
FirebaseUser loggedInUser;

// Example holidays
final Map<DateTime, List> _holidays = {
  DateTime(2019, 1, 1): ['New Year\'s Day'],
  DateTime(2019, 1, 6): ['Epiphany'],
  DateTime(2019, 2, 14): ['Valentine\'s Day'],
  DateTime(2019, 4, 21): ['Easter Sunday'],
  DateTime(2019, 4, 22): ['Easter Monday'],
};

class CalenderScreen extends StatefulWidget {
  @override
  _CalenderScreenState createState() => _CalenderScreenState();
}

class _CalenderScreenState extends State<CalenderScreen>
    with TickerProviderStateMixin {
  DateTime _selectedDay;
  Map<DateTime, List> _events = {};
  Map<DateTime, List> _visibleEvents;
  Map<DateTime, List> _visibleHolidays;
  List _selectedEvents;
  AnimationController _controller;
  final _auth = FirebaseAuth.instance;
  Widget streamBuilder;
  Widget buildEvents;

  @override
  void initState() {
    print("calender");
    super.initState();
    getCurrentUser();
    _selectedDay = DateTime.now();
    _selectedEvents = _events[_selectedDay] ?? [];
    _visibleEvents = _events;
    _visibleHolidays = _holidays;

    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 400),
    );

    _controller.forward();
  }

  void getCurrentUser() async {
    try {
      final user = await _auth.currentUser();
      if (user != null) {
        loggedInUser = user;
        setStreamBuilder();
      }
    } catch (e) {
      print(e);
    }
  }

  void setStreamBuilder() {
    setState(() {
      streamBuilder = StreamBuilder<QuerySnapshot>(
        stream: _firestore
            .collection('users')
            .document(loggedInUser.uid)
            .collection('history')
            .snapshots(),
        builder: (context, snapshot) {
          if (snapshot.data == null)
            return Center(child: CircularProgressIndicator());
          final historys = snapshot.data.documents;
          _events = {};
          for (var history in historys) {
            DateTime timeStamp = history.data['date'].toDate();
            DateTime currentDate =
                DateTime(timeStamp.year, timeStamp.month, timeStamp.day);
            if (_events.containsKey(currentDate)) {
              _events[currentDate].add(history);
            } else {
              _events[currentDate] = [history];
            }
          }
          print(_events);
          DateTime now = DateTime.now();
          _selectedDay = DateTime(now.year, now.month, now.day);
      //here i set the _selectedEvents
          _selectedEvents = _events[_selectedDay] ?? [];
          _visibleEvents = _events;
          return _buildTableCalendar();
        },
      );
    });
  }

  void _onDaySelected(DateTime day, List events) {
    setState(() {
      _selectedDay = day;
      _selectedEvents = events;
    });
  }

  void _onVisibleDaysChanged(
      DateTime first, DateTime last, CalendarFormat format) {
    setState(() {
      _visibleEvents = Map.fromEntries(
        _events.entries.where(
          (entry) =>
              entry.key.isAfter(first.subtract(const Duration(days: 1))) &&
              entry.key.isBefore(last.add(const Duration(days: 1))),
        ),
      );

      _visibleHolidays = Map.fromEntries(
        _holidays.entries.where(
          (entry) =>
              entry.key.isAfter(first.subtract(const Duration(days: 1))) &&
              entry.key.isBefore(last.add(const Duration(days: 1))),
        ),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color(0xFF232D3D),
      body: Column(
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          streamBuilder != null
              ? streamBuilder
              : Center(
                  child: CircularProgressIndicator(),
                ),
          const SizedBox(height: 8.0),
          _buildEventList()
        ],
      ),
      floatingActionButton: FloatingPenButton(),
    );
  }

  Widget _buildTableCalendar() {
    return TableCalendar(
      ~~
    );
  }

  Widget _buildEventList() {
    print("bulid event");
    return Expanded(
      child: ListView(
        children: _selectedEvents
            .map(
              (event) => HistoryCard(
                history: HistoryData(
                    ~~
              ),
            )
            .toList(),
      ),
    );
  }
}

This has been viewed enough that we are all experiencing/searching the same thing. Basically the initial load does not update the state when the streambuilder first loads. If you click and select a day, then it seems to load fine and populate with the events. If anyone can advise why it doesn't rebuild the widget when the stream gets populated by default that would be appreciated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM