flutter setState 不添加小部件

问题描述

这是我的代码。当您在上面的字段中输入一个城市然后按加号按钮时,它应该添加一个列表磁贴。但事实并非如此!有一个 listView,其中包含所有列表图块。 listView 应该显示列表中的所有列表图块。 当我按下按钮时,会打印一条消息以指示城市的数量。它显示城市已添加,但屏幕上没有任何变化。 ColorfulBox 是我构建的一个小部件。只是一种装饰。

import 'package:Flutter/material.dart';
import 'package:learner/logic/Weather.dart';
import 'ColorfulBox.dart';

class CitiesScreen extends StatefulWidget{
  @override
  _CitiesScreenState createState() => _CitiesScreenState();
}
class _CitiesScreenState extends State<CitiesScreen>{
  List<Weather> weatherData = List<Weather>();
  String cityName;
  List<Widget> cities = List<Widget>();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 20,horizontal: 10),child: Column(
          children: <Widget>[
            DecoratedBox(
              decoration: Boxdecoration(color: Colors.blueAccent,borderRadius: BorderRadius.circular(10),gradient: LinearGradient(colors: [Colors.blue,Colors.purple]) ),child: ColorfulBox(Padding(
                padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),child: ListTile(
                  title: TextField(onChanged: (value){
                    cityName = value;
                  },style: TextStyle(fontSize: 20,color: Colors.white),),trailing: FlatButton(
                    child: Icon(Icons.add,size: 30,color: Colors.white,onpressed: (){
                      setState(() {
                        addCity(cityName);
                        print(cities.length);
                      });
                    },)
            ),SizedBox(height: 30,Expanded(
              child: ListView(
                shrinkWrap: true,scrollDirection: Axis.vertical,children: cities,)
          ],);
  }

  void addCity(String city){
    weatherData.add(Weather(city: city));
    Container toBeAddedCity = Container(
      margin: const EdgeInsets.symmetric(vertical: 20,child:  Text(city,style: TextStyle(fontSize: 22,);
    cities.add(ColorfulBox(toBeAddedCity));
  }

}

你能帮我解决这个问题吗?我不知道! 是不是因为addCity方法在build方法之外?或者它添加不显示

解决方法

您可以只使用 ListView.builder(...) 来创建您的小部件。请不要将小部件存储为状态。

示例:

class CitiesScreen extends StatefulWidget {
  @override
  _CitiesScreenState createState() => _CitiesScreenState();
}

class _CitiesScreenState extends State<CitiesScreen> {
  final TextEditingController _controller = TextEditingController();
  final List<Weather> _weatherData = <Weather>[];
  final Random _rand = Random();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 20,horizontal: 10),child: Column(
          children: <Widget>[
            DecoratedBox(
              decoration: const BoxDecoration(
                color: Colors.blueAccent,borderRadius: BorderRadius.all(Radius.circular(10)),gradient: LinearGradient(
                  colors: <Color>[Colors.blue,Colors.purple],),child: Container(
                //ColorfulBox(
                color: Colors.blue,child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 10),child: ListTile(
                    title: TextField(
                      controller: _controller,style: const TextStyle(fontSize: 20,color: Colors.white),trailing: FlatButton(
                      child: const Icon(
                        Icons.add,size: 30,color: Colors.white,onPressed: () {
                        setState(() {
                          _weatherData.add(Weather(city: _controller.text));
                        });
                        _controller.clear();
                      },const SizedBox(height: 30),Expanded(
              child: ListView.builder(
                shrinkWrap: true,itemCount: _weatherData.length,itemBuilder: (_,int index) => ListTile(
                  tileColor: Color.fromARGB(
                    255,_rand.nextInt(255),title: Text(
                    _weatherData[index].city,style: const TextStyle(
                      fontSize: 22,)
          ],);
  }
}
,

首先,获取 TextField 值的一种便捷方法是使用 TextEditingController,而不是使用变量:

// Create a controller
final TextEditingController _textController = TextEditingController();

// Then use it in your TextField 
TextField(
   controller: _textController,// ... other lines

   trailing: FlatButton(
   onPressed: () {

     // Use the TextController's value
     setState(() {
       addCity(_textController.text);
     });

     // Clear the text after using it
     _textController.clear();
     },

因为您只更新了 cities 数组的内容,但保留了与 ListView 的子级相同的 cities 数组,所以 Flutter 假设状态没有改变,因此不会更新 UI。有两种方法可以解决这个问题:

  1. 改变整个列表(不推荐用于大量项目):
// Set new value to the list,instead of just adding items in
cities = List.from(cities)..add(ColorfulBox(toBeAddedCity)); 
  1. 使用 ListView.builder() 来跟踪您的列表的长度(在添加/删除项目时会修改)(推荐)
ListView.builder(
   itemCount: cities.length,itemBuilder: (context,index) => cities[index]
   // ... other lines

工作代码:


import 'package:flutter/material.dart';
import 'package:learner/logic/Weather.dart';
import 'ColorfulBox.dart';

class CitiesScreen extends StatefulWidget {
  @override
  _CitiesScreenState createState() => _CitiesScreenState();
}

class _CitiesScreenState extends State<CitiesScreen> {
  final TextEditingController _textEditingController = TextEditingController();
  List<Weather> weatherData = List<Weather>();
  String cityName;
  List<Widget> cities = List<Widget>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 20,child: Column(
          children: <Widget>[
            DecoratedBox(
                decoration: BoxDecoration(color: Colors.blueAccent,borderRadius: BorderRadius.circular(10),gradient: LinearGradient(
                        colors: [Colors.blue,Colors.purple])),child: ColorfulBox(Padding(
                  padding: const EdgeInsets.symmetric(
                      vertical: 10,horizontal: 0),child: ListTile(
                    title: TextField(
                      controller: _textEditingController,style: TextStyle(fontSize: 20,trailing: FlatButton(
                      child: Icon(Icons.add,onPressed: () {
                        setState(() {
                          addCity(_textController.text);
                          _textController.clear();
                          print(cities.length);
                        });
                      },)
            ),SizedBox(height: 30,scrollDirection: Axis.vertical,itemCount: cities.length,index) => cities[index],);
  }

  void addCity(String city) {
    weatherData.add(Weather(city: city));
    Container toBeAddedCity = Container(
      margin: const EdgeInsets.symmetric(vertical: 20,child: Text(city,style: TextStyle(fontSize: 22,);
    cities.add(ColorfulBox(toBeAddedCity));
  }
}