Flutter 未更新其动画文本小部件 (Animated_Text_kit)
Flutter not updating its animated text widget (Animated_Text_kit)
所以这是我从 json 获取数据并更新我的 UI 的主要代码。
我在与问题相关的代码所在的位置放置了“//Area of Interest”注释。
class MainScreen extends StatefulWidget {
final curLocdata;
MainScreen({this.curLocdata});
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
Weather weather = Weather();
var cityName;
int temp;
int temp_min;
int temp_max;
Icon weatherIcon;
//Area of Interest 1
RotateAnimatedTextKit textSum;//created a widget of RotateAnimatedTextKit library.
String st;
//Area of Interest 2
@override
void initState() {
// TODO: implement initState
super.initState();
updateUI(widget.curLocdata);//calling update function to rebuild my UI state with new data
}
void updateUI(data) {
setState(() {
if (data == null) {
temp = 0;
cityName = 'Error';
weatherIcon = Icon(Icons.error);
return;
}
cityName = data['name'];
temp = data['main']['temp'].toInt();
temp_min = data['main']['temp_min'].toInt();
temp_max = data['main']['temp_max'].toInt();
var condition = data['weather'][0]['id'];
weatherIcon = weather.getIcon(condition);
textSum = weather.getMessage(temp);//Area of Interest 3
st = weather.subtext(condition);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: () async {
updateUI(await Network().getData());
},
child: Icon(
FontAwesomeIcons.locationArrow,
),
),
SizedBox(
width: 180.0,
child: TextLiquidFill(
waveDuration: Duration(seconds: 3),
loadDuration: Duration(seconds: 10),
text: 'OpenWeather',
waveColor: Colors.red,
boxBackgroundColor: Color(0xFF1B1B1D),
textStyle: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.bold,
fontFamily: 'Source Sans Pro',
),
boxHeight: 50.0,
),
),
FlatButton(
onPressed: () async {
String SName = await Navigator.push(context,
MaterialPageRoute(builder: (context) {
return Search();
}));
if (SName != null) {
updateUI(await Network().getDataName(
SName));
}
},
child: Icon(
Icons.add,
color: Colors.white,
size: 40,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(50, 50, 50, 0),
child: Row(
children: <Widget>[
SizedBox(
// margin: EdgeInsets.fromLTRB(0, 50, 260, 0),
child: TypewriterAnimatedTextKit(
totalRepeatCount: 200,
isRepeatingAnimation: true,
speed: Duration(milliseconds: 700),
text: [cityName,],
textAlign: TextAlign.left,
textStyle: TextStyle(
fontSize: 20,
fontFamily: 'Source Sans Pro',
),
),
),
],
)),
Expanded(
flex: 9,
child: Container(
margin: EdgeInsets.fromLTRB(50, 30, 50, 80),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
//mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
'$temp°',
style: TextStyle(
fontSize: 80,
fontWeight: FontWeight.bold,
fontFamily: 'Source Sans Pro',
),
),
),
),
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
st,
style: TextStyle(
fontSize: 30,
fontFamily: 'Source Sans Pro',
color: Colors.grey[500]),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 50),
child: Container(
child: textSum,//Used this textSum to show my animated text. problem
Area of Interest 4
),
),
Expanded(
child: SizedBox(
//width: double.infinity,
//height: 100,
child: Divider(
color: Colors.red,
),
),
),
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 38),
child: Text(
'$temp_min° - $temp_max°',
style: TextStyle(
fontSize: 20,
color: Colors.grey[500],
fontFamily: 'Source Sans Pro',
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 20),
//padding: const EdgeInsets.all(8.0),
child: AvatarGlow(
endRadius: 30.0, //required
child: Material(
//required
elevation: 0.0,
shape: CircleBorder(),
child: CircleAvatar(
//backgroundColor: Colors.grey[100],
child: weatherIcon
// radius: 40.0,
//shape: BoxShape.circle
),
),
),
),
)
],
)`enter code here`
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xFF0C0C0C),
),
),
),
现在 weather.dart 文件,我从中返回 RotateAnimatedTextKit 小部件,具体取决于条件
class Weather{
//This return RotateAnimatedTextKit which is then held by textSum and is put as a child inside a container in MainScreen
RotateAnimatedTextKit getMessage(int temp) {
if (temp > 25) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 40,
text: ['It\'s ','time and','drink plenty','of water'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.topStart // or Alignment.topLeft
);
} else if (temp > 20) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 50,
text: ['Time for','shorts','','but keep','some warm','clothes handy'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart// or Alignment.topLeft
);
} else if (temp < 10) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 50,
text: ['You\'ll need','a ','and','a ','and a hot', 'soup and turkey'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart // or Alignment.topLeft
);
} else {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
transitionHeight: 50,
totalRepeatCount: 200,
text: ['Bring a','','just in case','and also avoid', 'cold breeze','and cold drinks'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart // or Alignment.topLeft
);
}
}
问题是即使条件不同,UI 也不会更新。那么为什么小部件树不更新的任何解决方案?但它只运行默认文本。此外,TextLiquidFill
下的 cityName
不会更新。
您可以使用 WidgetsBinding.instance.addPostFrameCallback
详细可以参考https://www.didierboelens.com/faq/week2/
代码片段
@override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
updateUI(widget.curLocdata);
});
}
简答:
使用按键
示例:
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:flutter/material.dart';
class MyAnimatedText extends StatefulWidget {
const MyAnimatedText({Key? key}) : super(key: key);
@override
State<MyAnimatedText> createState() => _MyAnimatedTextState();
}
class _MyAnimatedTextState extends State<MyAnimatedText> {
bool isDarkMode = true;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: isDarkMode ? Colors.grey[850] : Colors.amber[300]),
child: Column(
children: [
Container(
alignment: Alignment.topRight,
child: IconButton(
onPressed: () {
setState(() {
isDarkMode = !isDarkMode;
});
},
icon: Icon(isDarkMode ? Icons.light_mode : Icons.dark_mode))),
Padding(
padding: const EdgeInsets.all(15.0),
child: AnimatedTextKit(
key: ValueKey<bool>(isDarkMode),
animatedTexts: [
TypewriterAnimatedText(
isDarkMode ? 'Have a nice evening ;)' : 'Have a nice day :)',
cursor: isDarkMode ?'>':'<',
textStyle: TextStyle(
fontSize: 38,
color: isDarkMode ? Colors.amber[300] : Colors.grey[850]),
speed: const Duration(milliseconds: 100),
),
],
),
),
],
),
);
}
}
结果:
背景资料
当我尝试实现暗/亮变化时,我遇到了同样的问题。背景颜色在另一个小部件中定义并更改,字体颜色在 TypewriterAnimatedText 小部件中定义并且仅在第二个循环中更改。 runnig 动画中颜色没有变化。
解决方法:使用Keys
Animation 不会改变,因为 Flutter 试图保持 StatefulWidget 的状态,而 AnimatedTextKit 是一个 Stateful Widget。
要强制重建,您可以使用密钥。
可以在这里找到一篇不错的文章:How to force a Widget to redraw in Flutter?
所以这是我从 json 获取数据并更新我的 UI 的主要代码。 我在与问题相关的代码所在的位置放置了“//Area of Interest”注释。
class MainScreen extends StatefulWidget {
final curLocdata;
MainScreen({this.curLocdata});
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
Weather weather = Weather();
var cityName;
int temp;
int temp_min;
int temp_max;
Icon weatherIcon;
//Area of Interest 1
RotateAnimatedTextKit textSum;//created a widget of RotateAnimatedTextKit library.
String st;
//Area of Interest 2
@override
void initState() {
// TODO: implement initState
super.initState();
updateUI(widget.curLocdata);//calling update function to rebuild my UI state with new data
}
void updateUI(data) {
setState(() {
if (data == null) {
temp = 0;
cityName = 'Error';
weatherIcon = Icon(Icons.error);
return;
}
cityName = data['name'];
temp = data['main']['temp'].toInt();
temp_min = data['main']['temp_min'].toInt();
temp_max = data['main']['temp_max'].toInt();
var condition = data['weather'][0]['id'];
weatherIcon = weather.getIcon(condition);
textSum = weather.getMessage(temp);//Area of Interest 3
st = weather.subtext(condition);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: () async {
updateUI(await Network().getData());
},
child: Icon(
FontAwesomeIcons.locationArrow,
),
),
SizedBox(
width: 180.0,
child: TextLiquidFill(
waveDuration: Duration(seconds: 3),
loadDuration: Duration(seconds: 10),
text: 'OpenWeather',
waveColor: Colors.red,
boxBackgroundColor: Color(0xFF1B1B1D),
textStyle: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.bold,
fontFamily: 'Source Sans Pro',
),
boxHeight: 50.0,
),
),
FlatButton(
onPressed: () async {
String SName = await Navigator.push(context,
MaterialPageRoute(builder: (context) {
return Search();
}));
if (SName != null) {
updateUI(await Network().getDataName(
SName));
}
},
child: Icon(
Icons.add,
color: Colors.white,
size: 40,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(50, 50, 50, 0),
child: Row(
children: <Widget>[
SizedBox(
// margin: EdgeInsets.fromLTRB(0, 50, 260, 0),
child: TypewriterAnimatedTextKit(
totalRepeatCount: 200,
isRepeatingAnimation: true,
speed: Duration(milliseconds: 700),
text: [cityName,],
textAlign: TextAlign.left,
textStyle: TextStyle(
fontSize: 20,
fontFamily: 'Source Sans Pro',
),
),
),
],
)),
Expanded(
flex: 9,
child: Container(
margin: EdgeInsets.fromLTRB(50, 30, 50, 80),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
//mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
'$temp°',
style: TextStyle(
fontSize: 80,
fontWeight: FontWeight.bold,
fontFamily: 'Source Sans Pro',
),
),
),
),
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
st,
style: TextStyle(
fontSize: 30,
fontFamily: 'Source Sans Pro',
color: Colors.grey[500]),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 50),
child: Container(
child: textSum,//Used this textSum to show my animated text. problem
Area of Interest 4
),
),
Expanded(
child: SizedBox(
//width: double.infinity,
//height: 100,
child: Divider(
color: Colors.red,
),
),
),
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 38),
child: Text(
'$temp_min° - $temp_max°',
style: TextStyle(
fontSize: 20,
color: Colors.grey[500],
fontFamily: 'Source Sans Pro',
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 20),
//padding: const EdgeInsets.all(8.0),
child: AvatarGlow(
endRadius: 30.0, //required
child: Material(
//required
elevation: 0.0,
shape: CircleBorder(),
child: CircleAvatar(
//backgroundColor: Colors.grey[100],
child: weatherIcon
// radius: 40.0,
//shape: BoxShape.circle
),
),
),
),
)
],
)`enter code here`
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xFF0C0C0C),
),
),
),
现在 weather.dart 文件,我从中返回 RotateAnimatedTextKit 小部件,具体取决于条件
class Weather{
//This return RotateAnimatedTextKit which is then held by textSum and is put as a child inside a container in MainScreen
RotateAnimatedTextKit getMessage(int temp) {
if (temp > 25) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 40,
text: ['It\'s ','time and','drink plenty','of water'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.topStart // or Alignment.topLeft
);
} else if (temp > 20) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 50,
text: ['Time for','shorts','','but keep','some warm','clothes handy'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart// or Alignment.topLeft
);
} else if (temp < 10) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 50,
text: ['You\'ll need','a ','and','a ','and a hot', 'soup and turkey'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart // or Alignment.topLeft
);
} else {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
transitionHeight: 50,
totalRepeatCount: 200,
text: ['Bring a','','just in case','and also avoid', 'cold breeze','and cold drinks'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart // or Alignment.topLeft
);
}
}
问题是即使条件不同,UI 也不会更新。那么为什么小部件树不更新的任何解决方案?但它只运行默认文本。此外,TextLiquidFill
下的 cityName
不会更新。
您可以使用 WidgetsBinding.instance.addPostFrameCallback
详细可以参考https://www.didierboelens.com/faq/week2/
代码片段
@override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
updateUI(widget.curLocdata);
});
}
简答: 使用按键
示例:
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:flutter/material.dart';
class MyAnimatedText extends StatefulWidget {
const MyAnimatedText({Key? key}) : super(key: key);
@override
State<MyAnimatedText> createState() => _MyAnimatedTextState();
}
class _MyAnimatedTextState extends State<MyAnimatedText> {
bool isDarkMode = true;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: isDarkMode ? Colors.grey[850] : Colors.amber[300]),
child: Column(
children: [
Container(
alignment: Alignment.topRight,
child: IconButton(
onPressed: () {
setState(() {
isDarkMode = !isDarkMode;
});
},
icon: Icon(isDarkMode ? Icons.light_mode : Icons.dark_mode))),
Padding(
padding: const EdgeInsets.all(15.0),
child: AnimatedTextKit(
key: ValueKey<bool>(isDarkMode),
animatedTexts: [
TypewriterAnimatedText(
isDarkMode ? 'Have a nice evening ;)' : 'Have a nice day :)',
cursor: isDarkMode ?'>':'<',
textStyle: TextStyle(
fontSize: 38,
color: isDarkMode ? Colors.amber[300] : Colors.grey[850]),
speed: const Duration(milliseconds: 100),
),
],
),
),
],
),
);
}
}
结果:
背景资料
当我尝试实现暗/亮变化时,我遇到了同样的问题。背景颜色在另一个小部件中定义并更改,字体颜色在 TypewriterAnimatedText 小部件中定义并且仅在第二个循环中更改。 runnig 动画中颜色没有变化。
解决方法:使用Keys Animation 不会改变,因为 Flutter 试图保持 StatefulWidget 的状态,而 AnimatedTextKit 是一个 Stateful Widget。 要强制重建,您可以使用密钥。
可以在这里找到一篇不错的文章:How to force a Widget to redraw in Flutter?