Search code examples
flutterdartstatesetstatestate-management

Flutter: setState() working, but not re-rendering


I am learning flutter by making a little news app. Each tab has a list of news article widgets, that holds an image, a title, a description, a "Learn more" link button, and a button to expand or shrink the widget to include or hide the description.

My issue right now is with the expanding part. When I press the button to expand the widget, setState() is called and my boolean _expanded is toggled. However, I don't think it is being re-rendered, because the widget does not expand. As you'll see in my code, I have an inline conditional as a widget in the list in the form of _expanded ? option if its expanded : option if its not expanded. I've verified that the widgets are what I want them to be by putting a ! in front of the inline conditional and they display what they should, so I'm pretty stuck.

Currently my only idea is that it may have something to do with the fact that States are immutable and that maybe I am trying to change the state rather than replace and re-render. Any ideas? Thanks!

I tried to include only what is necessary, but here is some of the code:

class NewsList extends StatefulWidget {
  NewsList({this.keyword});
  final String keyword;

  @override
  createState() => NewsListState(keyword: keyword);
}

class NewsListState extends State<NewsList> {
  NewsListState({this.imageURLs, this.titles, this.texts, this.keyword});
  final List<String> imageURLs;
  final List<String> titles;
  final List<String> texts;
  final String keyword;

  List<NewsArticle> _newsArticles = List<NewsArticle>();

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

  @override
  void dispose() {
    super.dispose();
  }

  void _populateNewsArticles() {
    WebService().load(NewsArticle().all(keyword)).then((newsArticles) => {
          setState(() {
            _newsArticles = newsArticles;
          })
        });
  }

  Widget _buildNewsArticles(BuildContext build, int index) {
    bool _expanded = false;
    return Container(
      decoration: BoxDecoration(
          borderRadius: BorderRadius.all(const Radius.circular(10)),
          color: Colors.white,
          boxShadow: [
            BoxShadow(
                color: Colors.grey[300],
                blurRadius: 20,
                spreadRadius: 3,
                offset: Offset(5, 5))
          ]),
      child: Column(
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                _newsArticles[index].urlToImage == null
                    ? AssetImage(Constants.NEWS_PLACEHOLDER_IMAGE_ASSET_URL)
                    : CachedNetworkImage(
                        imageUrl: _newsArticles[index].urlToImage),
                Padding(padding: const EdgeInsets.symmetric(vertical: 5)),
                Text(
                  _newsArticles[index].title,
                  textAlign: TextAlign.left,
                  style: TextStyle(
                    fontSize: 25,
                    fontWeight: FontWeight.w700,
                    height: 0.8,
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.fromLTRB(4, 15, 4, 0),
                  child: Platform.isIOS
                      ? CupertinoButton.filled(
                          child: Text(
                            "Learn More",
                            style: TextStyle(fontSize: 17),
                          ),
                          onPressed: () =>
                              navigateToUrl(_newsArticles[index].url),
                          pressedOpacity: 0.6,
                        )
                      : RaisedButton(
                          onPressed: () =>
                              navigateToUrl(_newsArticles[index].url),
                          color: Color.fromRGBO(0, 122, 255, 1.0),
                          animationDuration: Duration(milliseconds: 1000),
                          child: Text(
                            "Learn More",
                            style: TextStyle(fontSize: 16, color: Colors.white),
                          ),
                        ),
                ),
                !_expanded ? Text("test description") : Container(),
                !_expanded
                    ? IconButton(
                        icon: Icon(Icons.keyboard_arrow_up),
                        onPressed: () => setState(() {
                          _expanded = !_expanded;
                        }),
                      )
                    : IconButton(
                        icon: Icon(Icons.keyboard_arrow_down),
                        onPressed: () {
                          setState(() {
                            debugPrint(_expanded.toString());
                            _expanded = !_expanded;
                            debugPrint(_expanded.toString());
                          });
                        },
                      ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget build(BuildContext context) {
    return ListView.separated(
      separatorBuilder: (BuildContext context, int index) =>
          Padding(padding: const EdgeInsets.symmetric(vertical: 15)),
      padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 30),
      itemBuilder: _buildNewsArticles,
      itemCount: _newsArticles.length,
    );
  }
}

Solution

  • _expanded is a local variable defined and initialised in the buildNewsArticles method. Therefore, every time buildNewsArticles runs, _expanded is initialised to false.

    You should move _expanded out of the method so that it is a member variable of NewsListState.