我创建了一个有状态小部件,它的父小部件需要调用一个生活在子状态的函数.
具体来说,我有一个类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 次  |  
        
|   最近记录:  |