我无法从其他类访问Flutter中的对象(或状态)实例。我已经尝试过在网络上使用类似问题进行许多摆弄,并且目前正在使用“ GlobalKey”,但是我无法使其正常工作。
我正在尝试制作一个简单的Flutter应用程序,在此应用程序上,只需按一下按钮即可从另一个类访问Widget的状态:
import 'viewer.dart' as viewer;
(...)
onPressed: () {
//Works
print("Doing something");
//Doesn't work
viewer.key.currentState.nextPage();
},
我的viewer.dart文件看起来包含一个PageController,以及一个包含该控制器的类:
final key = new GlobalKey<_RegistryState>();
final PageController _controller = PageController(
initialPage: 0,
);
class Registry extends StatefulWidget {
Registry({ Key key }) : super(key: key);
@override
_RegistryState createState() => _RegistryState();
}
class _RegistryState extends State<Registry> {
void next() {
print("Doing something!");
_controller.nextPage();
}
@override
Widget build(BuildContext context) {
return PageView(
//physics: NeverScrollableScrollPhysics(), //Disable user manually scrolling
controller: _controller,
children: [
registry_screens.ScreenSplash(),
registry_screens.ScreenName(),
Text("Bye"),
],
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
这个想法是,每当按下按钮时,PageController就会移至下一页(已经存在,我可以通过在屏幕上滑动来手动滚动到下一页)。
该应用程序编译正常,但是当按下按钮时,出现错误信息'NoSuchMethodError:null无效成员:'next'。
我是否使用正确的方法访问小部件(或状态)实例?
答案 0 :(得分:1)
从外部访问状态通常不是一个好主意。相反,外部类只能通过它们公开的方法与Widget进行交互。
我刚刚制作了一个视频,演示了如何使用PageView
完全相同的入门设置,您可以在这里看到它-我逐步进行操作:https://www.youtube.com/watch?v=ji__FEKSnMw >
本质上,它看起来像这样:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MainPage(),
debugShowCheckedModeBanner: false,
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key key}) : super(key: key);
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
PageController pageController = new PageController(initialPage: 0);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Container(
child: PageView(
controller: pageController,
physics: NeverScrollableScrollPhysics(),
children: [
Slide(
hero: Image.asset("./assets/hero-1.png"),
title: "Boost your traffic",
subtitle:
"Outreach to many social networks to improve your statistics",
onNext: nextPage),
Slide(
hero: Image.asset("./assets/hero-2.png"),
title: "Give the best solution",
subtitle:
"We will give best solution for your business isues",
onNext: nextPage),
Slide(
hero: Image.asset("./assets/hero-3.png"),
title: "Reach the target",
subtitle:
"With our help, it will be easier to achieve your goals",
onNext: nextPage),
Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Text(
'Be kind to yourself',
style: kTitleStyle,
),
),
)
])),
),
);
}
void nextPage() {
pageController.nextPage(
duration: const Duration(milliseconds: 200), curve: Curves.ease);
}
}
class Slide extends StatelessWidget {
final Widget hero;
final String title;
final String subtitle;
final VoidCallback onNext;
const Slide({Key key, this.hero, this.title, this.subtitle, this.onNext})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: hero),
Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Text(
title,
style: kTitleStyle,
),
SizedBox(
height: 20,
),
Text(
subtitle,
style: kSubtitleStyle,
textAlign: TextAlign.center,
),
SizedBox(
height: 35,
),
],
),
),
GestureDetector(
onTap: onNext,
child: Text(
"Skip",
style: kSubtitleStyle,
),
),
SizedBox(
height: 4,
)
],
),
);
}
}
答案 1 :(得分:1)
Flutter是一个声明性框架。在这种环境中,每当您要更改视图(或界面)时,都需要重建它。而且,如果您重建保持状态的内容,则会使其失去状态。这就是为什么它不应该负责保持程序状态的原因。
Flutter中的状态管理是一个广泛的主题,有很多选择。正如@ DrSatan1在评论中提到的那样,在Flutter.dev中可以找到有关使用Provider进行状态管理的很好的文档,但是您可以使用BLoC,ReduX,{{ 3}}等。
在您的特定情况下,由于它比较简单,因此可以使用全局对象或Inherited Widget
来实现。
全局对象
globals.dart
currentPage=0;
在小部件中
import 'globals.dart' as global;
(...)
onPressed: () {
setState((){
globals.currentPage++;
});
},
viewer.dart
@override
Widget build(BuildContext context) {
return PageView(
//physics: NeverScrollableScrollPhysics(), //Disable user manually scrolling
currentPage: globals.currentPage, //instead of using PageController
children: [
registry_screens.ScreenSplash(),
registry_screens.ScreenName(),
Text("Bye"),
],
);
}
您可以将PageController
用作全局对象。在这种情况下,您可以将PageController沿小部件树传递。在这种情况下,最好使用InheritedWidget
。
InheritedWidget
根据MobX,InheritedWidget
是
widget的基类,这些widget有效地将信息向下传播 树。
您可以将PageController传递给树下的所有小部件。您的viewer.dart将是:
(...)
@override
Widget build(BuildContext context) {
return MyInheritedWidget (
pageController: _controller,
child: PageView(
//physics: NeverScrollableScrollPhysics(), //Disable user manually scrolling
//controller: _controller, // Don't pass controller here
children: [
registry_screens.ScreenSplash(),
registry_screens.ScreenName(),
Text("Bye"),
],
);
);
}
(...)
// create the inherited widget wrapper. It could be done with [Builder][7] too, instead of a different Widget.
class MyInheritedWidget extends InheritedWidget {
final PageController pageController;
MyInheritedWidget({
Key key,
@required Widget child,
@required this.pageController,
}) : super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
}
(...)
之后,您可以在PageView或其下的任何小部件中访问pageController。
(...)
onPressed: () {
//Works
print("Doing something");
// Find closest InheritedWidget
MyInheritedWidget myInheritedWidget =
context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>()
// Get pageController from it
PageController controller = myInheritedWidget.pageController
// call nextPage()
nextPage();
},
(...)
尽管这两种方法都可以在您的特定情况下使用,但是您应该检查Flutter Docs中有关状态管理的信息。也许您根本不需要PageController。