在 Flutter 中使用 ChangeNotifierProvider 时,消费者之外的小部件也会得到重建
Widgets present outside the Consumer are also getting rebuilt while using ChangeNotifierProvider in Flutter
所以我只是在玩弄提供程序小部件。下面是我的 Entry 主函数。
void main() async {
runApp(
ChangeNotifierProvider<GameProvider>(
create: (_) => GameProvider(),
builder: (context,child) => MaterialApp(home: GameScene()),
)
);
}
如上面的代码所示,我在 MaterialApp 上方添加了提供程序小部件,以便它可以在整个应用程序中使用。
下面是我的 GameScene 小部件:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:river_crossing_game/Providers/GameProvider.dart';
class GameScene extends StatefulWidget {
@override
_GameSceneState createState() => _GameSceneState();
}
class _GameSceneState extends State<GameScene> with SingleTickerProviderStateMixin{
double height, width;
bool pseudoInitState = true;
AnimationController _animationController;
Animation _animation;
GameProvider _provider;
@override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
if(pseudoInitState){
_provider = Provider.of<GameProvider>(context); /// Added this just to use the methods present inside the provider class
_animationController = AnimationController(vsync: this,duration: Duration(seconds: 5));
_animation = Tween<double>(begin: 0,end: 60 * 5.0).animate(_animationController);
_provider.initPlankPos(Offset(0,height * 0.4)); /// Ignore this method
_animation.addListener(() {
_provider.translatePlank(_animation.value, Offset(1,0)); /// This one is just updating the position of the widget inside the Consumer
});
_animationController.forward();
pseudoInitState = false;
}
return Material(
child: Stack(
children: [
Container(height: height, width: width, color: Colors.lightBlue,),
Align(
alignment: Alignment.bottomCenter,
child: Builder(builder: (context) {print("Background Build ${Random.secure().nextDouble().toString()}");return Image.asset('assets/grass_sprite.png',height: 90,width: width,fit: BoxFit.cover);}),
),
Consumer<GameProvider>(
child: Image.asset('assets/wood_plank.png',height: width * 0.15,width: width * 0.25,fit: BoxFit.cover,),
builder: (context,value, child) {
return Transform.translate(
offset: Offset(value.plankPosX,value.plankPosY),
child: child,
);
}
)
],
),
);
}
}
如上面的代码所示,我用 Consumer 包装了 Image 小部件,因为它是唯一一个每次提供者提供新值时都会移动到新位置的小部件,并休息所有其他小部件(草精灵图像和堆栈上方的蓝色容器)将保持不变,无论提供者的更新如何。
为了检查它是否按照我上面所说的方式工作,我用 Builder 包装了草精灵图像小部件(如上面的代码所示)以检查它是否正在重建,即使它在 Consumer 小部件之外也是如此,并且遗憾的是,它在每次更新时都会重建。
直到现在我认为只有 Consumer 的 builder 函数内的小部件会被重建,而新值由提供者提供,但这里 Consumer 之外的小部件也会被重建。
我是否没有正确使用提供者,或者我是否得到了有关提供者工作的错误信息?
提前感谢您的帮助。
_provider = Provider.of<GameProvider>(context);
改成这样:
_provider = Provider.of<GameProvider>(context,listen: false );
所以我只是在玩弄提供程序小部件。下面是我的 Entry 主函数。
void main() async {
runApp(
ChangeNotifierProvider<GameProvider>(
create: (_) => GameProvider(),
builder: (context,child) => MaterialApp(home: GameScene()),
)
);
}
如上面的代码所示,我在 MaterialApp 上方添加了提供程序小部件,以便它可以在整个应用程序中使用。
下面是我的 GameScene 小部件:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:river_crossing_game/Providers/GameProvider.dart';
class GameScene extends StatefulWidget {
@override
_GameSceneState createState() => _GameSceneState();
}
class _GameSceneState extends State<GameScene> with SingleTickerProviderStateMixin{
double height, width;
bool pseudoInitState = true;
AnimationController _animationController;
Animation _animation;
GameProvider _provider;
@override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
if(pseudoInitState){
_provider = Provider.of<GameProvider>(context); /// Added this just to use the methods present inside the provider class
_animationController = AnimationController(vsync: this,duration: Duration(seconds: 5));
_animation = Tween<double>(begin: 0,end: 60 * 5.0).animate(_animationController);
_provider.initPlankPos(Offset(0,height * 0.4)); /// Ignore this method
_animation.addListener(() {
_provider.translatePlank(_animation.value, Offset(1,0)); /// This one is just updating the position of the widget inside the Consumer
});
_animationController.forward();
pseudoInitState = false;
}
return Material(
child: Stack(
children: [
Container(height: height, width: width, color: Colors.lightBlue,),
Align(
alignment: Alignment.bottomCenter,
child: Builder(builder: (context) {print("Background Build ${Random.secure().nextDouble().toString()}");return Image.asset('assets/grass_sprite.png',height: 90,width: width,fit: BoxFit.cover);}),
),
Consumer<GameProvider>(
child: Image.asset('assets/wood_plank.png',height: width * 0.15,width: width * 0.25,fit: BoxFit.cover,),
builder: (context,value, child) {
return Transform.translate(
offset: Offset(value.plankPosX,value.plankPosY),
child: child,
);
}
)
],
),
);
}
}
如上面的代码所示,我用 Consumer 包装了 Image 小部件,因为它是唯一一个每次提供者提供新值时都会移动到新位置的小部件,并休息所有其他小部件(草精灵图像和堆栈上方的蓝色容器)将保持不变,无论提供者的更新如何。
为了检查它是否按照我上面所说的方式工作,我用 Builder 包装了草精灵图像小部件(如上面的代码所示)以检查它是否正在重建,即使它在 Consumer 小部件之外也是如此,并且遗憾的是,它在每次更新时都会重建。
直到现在我认为只有 Consumer 的 builder 函数内的小部件会被重建,而新值由提供者提供,但这里 Consumer 之外的小部件也会被重建。
我是否没有正确使用提供者,或者我是否得到了有关提供者工作的错误信息?
提前感谢您的帮助。
_provider = Provider.of<GameProvider>(context);
改成这样:
_provider = Provider.of<GameProvider>(context,listen: false );