我创建了一个有状态小部件,它的父小部件需要调用一个生活在子状态的函数.
具体来说,我有一个类PlayerContainer,它创建一个VideoPlayer并具有VideoPlayerController的成员变量.当我按下播放按钮时,我的主类需要在状态的VideoPlayerController上调用play(),所以我在State类中创建了一个函数,但我不知道如何从父窗口小部件访问该函数.
这甚至可能吗?或者我这样做是错的?
Dar*_*ole 13
我知道我参加派对的时间已经很晚了,但我觉得我认为可能有所帮助.所以,你需要在你的VideoPlayerController
班级做四(4)件事:
1.创建你的州级实例.
2.创建一个可在PlayerContainer
类
3中访问的方法(播放).在您的方法中,使用VideoPlayerControllerState
实例在您的州类中调用该方法.
4.最后,当您createState
使用已创建的实例执行此操作时.
class VideoPlayerController extends StatefulWidget {
final VideoPlayerControllerState vpcs = VideoPlayerControllerState();
void play() {
vpcs.play();
}
@override
State<StatefulWidget> createState() => vpcs;
}
Run Code Online (Sandbox Code Playgroud)
如您所见,该play
方法使用vpcs
(VideoPlayerControllerState实例)来调用状态类中已有的play方法.
在您的PlayerContainer类中,使用您的成员变量来调用play方法.
class PlayerContainerState extends State<PlayerContainer> {
VideoPlayerController _vpc;
@override
void initState() {
super.initState();
_vpc = VideoPlayerController();
}
...
void _handlePressPlay(){
_vpc.play();
}
...
@override
Widget build(BuildContext context) {
return ... //your video player widget using _vpc as your VideoPlayerController
_vpc,
);
}
}
Run Code Online (Sandbox Code Playgroud)
您可以_handlePressPlay()
通过onPressed
播放按钮的方法拨打电话.或者,只需_vpc.play()
输入onPressed
方法即可.你的选择 :-).
虽然达伦·科尔的上述答案无法正常工作,但有一种简单的方法可以避免眼前的问题。代替
State<StatefulWidget> createState() => vpcs;
final VideoPlayerControllerState vpcs = VideoPlayerControllerState();
Run Code Online (Sandbox Code Playgroud)
写:
State<StatefulWidget> createState(){
vpcs = VideoPlayerControllerState();
return vpcs;
}
VideoPlayerControllerState vpcs;
Run Code Online (Sandbox Code Playgroud)
createState()
这样,每次调用时状态都会被重写,从而避免了Failed assertion: line 3819 pos 12: '_state._widget == null': is not true
错误。
不过,我想这是一个有点黑客的解决方案 - 有人能指出更好的解决方案吗?
状态管理是他们在这个框架方面放弃的一件事。我使用了静态变量(如果我需要在状态之间共享数据)和 GlobalKeys(仅用于一个快速、肮脏的解决方案)来完成这项工作。我们应该使用 InheritedWidgets,它对于一些应该很简单的东西来说是非常偏僻的。我通常只是这样做:
// top of code here - this is global
final videoPlayerKey = GlobalKey();
class VideoPlayerContainer extends StatelessWidget {
static VideoPlayerController videoPlayerController;
...
@override
Widget build(BuildContext context) {
videoPlayerController = VideoPlayerController(...);
// the static variable is empty until the container is built
return Container(
child: VideoPlayer(
child: PlayButton(onTap: () =>
videoPlayerKey.currentState.setState(
() => VideoPlayerContainer.videoPlayerController.play();
))
),
);
}
}
class VideoPlayer extends StatefulWidget {
final Key key = videoPlayerKey;
...
}
class VideoPlayerState extends State<VideoPlayer> {
...
}
Run Code Online (Sandbox Code Playgroud)
我们需要获取 videoPlayerKey 的 currentState 以使用 setState() 并重新运行 build 方法,以便它知道 update,然后我们可以使用静态变量获取存储在任何地方的播放器的控制器。它可以在 VideoPlayer 或 VideoPlayerContainer 中不存在的任何其他地方,因为它是静态的 - 将 GlobalKey 分配给需要重建的任何 Widget 是很重要的。它会起作用,因为每当用户可以点击按钮时,静态变量都会被设置为任何 void 以通过 VideoPlayerContainer 的 build() 方法读取。对于这种方法,重要的是要注意它'
注意:如果您尝试在一个布局中使用多个 VideoPlayer,这将不起作用,因为 GlobalKeys 必须是唯一的,并且所有 VideoPlayer 将使用相同的键进行初始化。这更像是一个肮脏的黑客。我目前正在研究一个更强大的状态管理解决方案来解决这样的问题。
通过一个简单的应用程序,您可以简单地在与视频播放器相同的小部件中创建播放按钮。通过将 PlayerContainer 与其父级组合,您可以增加 Widget State 范围的大小,以便需要访问它的所有内容都是单个较大 Widget 的一部分。
子 Widget 受祖先影响的主要方式是:使用不同的参数重建,或者监听祖先更改的内容。对于后者,您可以在子项的某处使用 InheritedWidget。如果子级引用 InheritedWidget,则当 IW 更改时,它会被重建。另一种方法是监听祖先生成的事件流。
您可能会发现最简单的方法是在一次构建中构建整个页面,直到这变得难以处理。
归档时间: |
|
查看次数: |
9363 次 |
最近记录: |