#flutter #widget #setstate
#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, horizontal: 10),
child: Text(city, style: TextStyle(fontSize: 22, color: Colors.white),),
);
cities.add(ColorfulBox(toBeAddedCity));
}
}
Можете ли вы помочь мне исправить это? Понятия не имею!
Это потому, что метод addCity отсутствует в методе сборки? или он добавляет, но не показывает его?
Ответ №1:
Вы можете просто использовать 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),
_rand.nextInt(255),
_rand.nextInt(255),
),
title: Text(
_weatherData[index].city,
style: const TextStyle(
fontSize: 22,
color: Colors.white,
),
),
),
),
)
],
),
),
);
}
}
Ответ №2:
Прежде всего, удобный способ получить значение текстового поля — использовать 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
массива, но сохраняете тот же cities
массив, что и дочерний элемент ListView, Flutter предполагает, что состояние не изменяется и, следовательно, не обновляет пользовательский интерфейс. Есть 2 способа решить эту проблему:
- Изменение всего списка (не рекомендуется для большого количества элементов):
// Set new value to the list, instead of just adding items in
cities = List.from(cities)..add(ColorfulBox(toBeAddedCity));
- Используйте
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, 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(
controller: _textEditingController,
style: TextStyle(fontSize: 20, color: Colors.white),),
trailing: FlatButton(
child: Icon(Icons.add, size: 30, color: Colors.white,),
onPressed: () {
setState(() {
addCity(_textController.text);
_textController.clear();
print(cities.length);
});
},
),
),
),
)
),
SizedBox(height: 30,),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: cities.length,
itemBuilder: (context, index) => cities[index],
),
)
],
),
),
);
}
void addCity(String city) {
weatherData.add(Weather(city: city));
Container toBeAddedCity = Container(
margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: Text(city, style: TextStyle(fontSize: 22, color: Colors.white),),
);
cities.add(ColorfulBox(toBeAddedCity));
}
}
Комментарии:
1. Большое вам спасибо. Он работает отлично. Я новичок в flutter, поэтому я делаю ужасные ошибки! 🙂