1

I'm creating a mobile application where users will select the video from the list and play. So I have built two widgets in a flutter, one for displaying a video list from a certain URL and the other one for playing a video when the user clicks the video from the list. I'm stacking on the way of dynamic picking URL from the list widget, I have tried to setState in the BuildContext method but does not seem to work. I have tried to initialize the video player inside a build method but does not work instead I get "(HTTPLog)-Static: isSBSettingEnabled false" and continue looping without ending I'm looking for anyways of getting these variables I sent through the "Navigator pushNamed" method from the video list page before the player initialized. or anything else which can help

I saw this answer 'https://stackoverflow.com/questions/56262655/flutter-get-passed-arguments-from-navigator-in-widgets-states-initstate' but I could not understand since I'm new to a flutter, i decided to ask again my be I can get a good answer

Thanks in advance!

I use the video_player flutter package and below are my code:

**video_players**

class PlayerWidget extends StatefulWidget {
  const PlayerWidget({Key? key}) : super(key: key);
  @override
  _PlayerWidgetState createState() => _PlayerWidgetState();
}

class _PlayerWidgetState extends State<PlayerWidget> {
  late VideoPlayerController _controller;
  dynamic videoData={};
  String vidUrl='https://videos.pond5.com/sunset-woman-running-ocean-reflection-footage-027692108_main_xxl.mp4';
  Duration? _duration;
  Duration?  _position;

  @override
  void initState() {
    super.initState();
    //change screen orientation method
    setScreenOrientations();
  }

  //orientations monitor
  Future setScreenOrientations() async{
    //change the screen orientation
    await SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeRight,DeviceOrientation.landscapeLeft,]);
    //remove status bar when on landscape mode
    await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
    // The following line will enable the Android and iOS wakelock.
    await Wakelock.enable();
  }

  Future removeOrientation() async{
    await SystemChrome.setPreferredOrientations(DeviceOrientation.values);
    //setback status bar
    await  SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom,SystemUiOverlay.top]);
    //let screen sleep if there is no activities
    Wakelock.disable();
  }



  //video progress bar
  Widget buildIndicator() => Padding(
    padding: const EdgeInsets.all(8.0),
    child: Column(
      children: [
        VideoProgressIndicator(
          _controller,
          allowScrubbing: true,
          colors: const VideoProgressColors(
            playedColor: Color(0xfff49043),
            bufferedColor: Colors.grey,
            backgroundColor: Colors.white30,
          ),
        ),
        Padding(
          padding: const EdgeInsets.all(16.0),
          child: Row(
            children: [
              Expanded(child: Text('${_printDuration(_position)} / ${_printDuration(_duration)}',style: const TextStyle(color: Colors.white),),),
              Expanded(child: Align(
                alignment: Alignment.center,
                child: GestureDetector(
                  onTap: (){},
                  child: RichText(text: TextSpan(children: [const WidgetSpan(child: Icon(Icons.speed_outlined,color: Colors.white, size: 16),),TextSpan(text: " Speed (${_controller.value.playbackSpeed})",style: const TextStyle(fontSize: 14)),],),),
                ),
              ),),
              Expanded(child: Align(
                alignment: Alignment.center,
                child: GestureDetector(
                  onTap: (){Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=> const Home()));},
                  child: RichText(text: const TextSpan(children: [WidgetSpan(child: Icon(Icons.video_library,color: Colors.white, size: 14),),TextSpan(text: " View Video",style: TextStyle(fontSize: 14)),],),),
                ),
              ),),
            ],
          ),
        )
      ],
    ),
  );

  //convert time to the human readable format
  String _printDuration(duration) {
    if(duration==null){ return '00:00'; }
    String twoDigits(int n) => n.toString().padLeft(2, "0");
    String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
    String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
    if(_duration?.inHours == 00){return "$twoDigitMinutes:$twoDigitSeconds";}
    else{return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";}
  }

  @override
  void dispose() {super.dispose();_controller.dispose();removeOrientation();}

  @override
  Widget build(BuildContext context) {

    //get all value sent from the video widget route and hold them
    videoData = ModalRoute.of(context)!.settings.arguments;
    setState((){ vidUrl = videoData['videoUrl'];});

    _controller = VideoPlayerController.network("${videoData['videoUrl']}")
      ..addListener(() {
        Timer.run(() {setState((){ _position = _controller.value.position;}); });
        setState(() {_duration = _controller.value.duration;});
      })
      ..initialize()
          .then((_) {});

    //play pause state listener to toggle the button
    Widget playPauseBtn() => _controller.value.isPlaying ? Container(alignment: Alignment.center,color: Colors.black26, child: const Icon(Icons.pause, color: Colors.white, size: 80),)
        : Container(alignment: Alignment.center,color: Colors.black26, child: const Icon(Icons.play_arrow, color: Colors.white, size: 80),);

    //overlay on the video player
    videoOverlay(){
      return GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () {setState(() {_controller.value.isPlaying ? _controller.pause() : _controller.play();});},
        child: Stack(children: <Widget>[playPauseBtn(),Positioned(bottom: 0,left: 0,right: 0,child: buildIndicator(),),],
        ),
      );
    }

    //video player stack
    Widget videoStack() => Stack(fit: StackFit.expand,children:[ AspectRatio(aspectRatio: _controller.value.aspectRatio,child: VideoPlayer(_controller),),]);

    //complete player
    Widget completePlayer() => Stack(children: <Widget>[videoStack(),Positioned.fill(child: videoOverlay()),],);

    return  Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        title: Text(videoData['videoName']),
        centerTitle: true,
        backgroundColor: Colors.transparent,
        elevation: 0,
        leading: IconButton(
          onPressed: () async {await SystemChrome.setPreferredOrientations(DeviceOrientation.values);Navigator.pop(context);},
          icon: const Icon(Icons.arrow_back_ios_outlined),
        ),
      ),
      backgroundColor: const Color(0xff121212),
      body: _controller.value.isInitialized ? Container(alignment: Alignment.topCenter, child: completePlayer()) : const Center(child: CircularProgressIndicator(),),
    );
  }
}
  • What data are you passing, and what are you expecting? – Josteve Jan 27 '22 at 14:24
  • when video clicked from the list, i'm pass an argument with the 3 value Navigator.push(context,MaterialPageRoute(builder: (context) => const PlayerWidget(),settings: RouteSettings(arguments: {'videoName': videoName,'videoUrl':videoUrl,'posterUrl':posterUrl},),),) – Deogratius Mabima Jan 27 '22 at 15:50
  • From this comment, you could easily use only `push` without `pushNamed`..Is there a reason why you want to use `pushNamed`? – Josteve Jan 27 '22 at 15:58
  • Nop!, the only thing that challenges me is to be able to catch that video URL in time, maybe when is initiated the state. because if I run that code the app just keeps loading the video. but if I take the video initialization out of the build method the video is load perfect – Deogratius Mabima Jan 27 '22 at 16:51
  • Check my answer out and let me know if it works for you. – Josteve Jan 27 '22 at 17:10

1 Answers1

1

Use Navigator.push instead.

Follow these steps:

1. Add videoData to the parameters of your widget and use widget.videoData to read in initState

class PlayerWidget extends StatefulWidget {
  final Map<String, dynamic> videoData;
  const PlayerWidget({Key? key, required this.videoData}) : super(key: key);
  @override
  _PlayerWidgetState createState() => _PlayerWidgetState();
}

class _PlayerWidgetState extends State<PlayerWidget> {
  late VideoPlayerController _controller;
  dynamic videoData={};
  String vidUrl='https://videos.pond5.com/sunset-woman-running-ocean-reflection-footage-027692108_main_xxl.mp4';
  Duration? _duration;
  Duration?  _position;

  @override
  void initState() {
    super.initState();
    //change screen orientation method
    videoData = widget.videoData;
    setState((){});
    setScreenOrientations();
  }

2. Use Navigator.push to navigate.

Navigator.push(context, MaterialPageRoute(builder: (_) => PlayerWidget(videoData: {'videoName': videoName,'videoUrl':videoUrl,'posterUrl':posterUrl}));
Josteve
  • 11,459
  • 1
  • 23
  • 35