颤振中的 ChewiePlayer 在进入全屏模式后处理控制器

ChewiePlayer in flutter disposes the controller after going to full screen mode

我在一个有状态小部件中有一个 ChewiePlayer,它正在另一个有状态小部件中使用。当我进入全屏模式时,会调用 dispose 函数,这基本上会删除侦听器,我无法退出全屏模式。 我也收到此错误:

NoSuchMethodError: The method 'dispose' was called on null. Receiver: null Tried calling: dispose()

以及

A ChewiePlayerController was used after being disposed. Once you have called dispose() on a ChewiePlayerController...

似乎是一个常见问题,尝试了几乎所有解决方案,但似乎没有任何效果。

这是我的 flutter doctor 输出:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.6, on Mac OS X 10.15.7 19H1217 darwin-x64,
    locale en-GB)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 12.1)
[✓] Android Studio (version 4.1)
[✓] VS Code (version 1.57.0)
[✓] Connected device (1 available)

• No issues found!

这是我的有状态小部件中的代码:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/style.dart' as HtmlStyle;
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:ria/src/models/game_pebble.dart';
import 'package:ria/src/models/trail.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';

class VideoOutputMineral extends StatefulWidget {
  @override
  VideoOutputMineralState createState() => VideoOutputMineralState();
  final Mineral mineral;
  final List<GameStyle> styles;
  final Function onChangeAnswer;

  VideoOutputMineral(this.mineral, this.styles, this.onChangeAnswer, {Key key})
      : super(key: key);
}

class VideoOutputMineralState extends State<VideoOutputMineral>
    with TickerProviderStateMixin {
  VideoPlayerController videoPlayerController;
  ChewieController chewieController;

  Color hexToColor(String code) {
    return new Color(int.parse(code.substring(1, 7), radix: 16) + 0xFF000000);
  }

  Color getFontColor() {
    if (widget.styles != null &&
        widget.styles.first != null &&
        widget.styles.first.attributes.fontColor != null) {
      return hexToColor(widget.styles.first.attributes.fontColor);
    } else {
      return Colors.black;
    }
  }

  Future<void> initializeVideoPlayer() async {
    // the async function which is responsible to get the trail detail, then initialize the video player controller, once done rebuild the widget with new data.
    if (widget.mineral.properties.first.media.url != null &&
        widget.mineral.properties.first.media.url != "") {
      videoPlayerController = VideoPlayerController.network(
          widget.mineral.properties.first.media.url);
      await videoPlayerController.initialize();
      chewieController = ChewieController(
        videoPlayerController: videoPlayerController,
        looping: true,
        aspectRatio: 16 / 9,
        deviceOrientationsAfterFullScreen: [
          DeviceOrientation.portraitUp,
          DeviceOrientation.portraitDown
        ],
        allowFullScreen: true,
        fullScreenByDefault: false,
        autoInitialize: true,
        errorBuilder: (context, errorMessage) {
          return Center(
            child: Text(
              errorMessage,
              style: TextStyle(color: Colors.white),
            ),
          );
        },
      );
    }
    setState(() {});
  }

  @override
  void initState() {
    this.initializeVideoPlayer();
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
    if (chewieController != null && chewieController.isFullScreen) {
      chewieController?.dispose();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 8, bottom: 8, left: 30, right: 30),
      child: Column(
        children: [
          widget.mineral.properties.first.title != null &&
                  widget.mineral.properties.first.title != ""
              ? Column(
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Expanded(
                          child: Linkify(
                            options: LinkifyOptions(
                                defaultToHttps: true, looseUrl: true),
                            onOpen: (link) async {
                              if (await canLaunch(link.url)) {
                                await launch(link.url);
                              } else {
                                throw 'Could not launch $link';
                              }
                            },
                            text:
                                "${widget.mineral.properties.first.title}${widget.mineral.properties?.first?.rulesInput?.rulesInputRequired == 'required' ? ' *' : ''}",
                            style: TextStyle(
                              fontSize: 20,
                              fontWeight: FontWeight.w500,
                              color: hexToColor(
                                  widget.styles.first.attributes.fontColor),
                            ),
                            linkStyle: TextStyle(
                              fontSize: 20,
                              fontWeight: FontWeight.w500,
                              color: hexToColor(
                                  widget.styles.first.attributes.fontColor),
                            ),
                            textAlign: TextAlign.center,
                          ),
                        ),
                      ],
                    ),
                    SizedBox(
                      height: 12,
                    ),
                  ],
                )
              : Container(),
          widget.mineral.properties.first.description != null &&
                  widget.mineral.properties.first.description != ""
              ? Column(
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Expanded(
                          child: Linkify(
                            options: LinkifyOptions(
                                defaultToHttps: true, looseUrl: true),
                            onOpen: (link) async {
                              if (await canLaunch(link.url)) {
                                await launch(link.url);
                              } else {
                                throw 'Could not launch $link';
                              }
                            },
                            text:
                                "${widget.mineral.properties.first.description}",
                            style: TextStyle(
                              fontSize: 17,
                              fontWeight: FontWeight.w500,
                              color: hexToColor(
                                  widget.styles.first.attributes.fontColor),
                            ),
                            linkStyle: TextStyle(
                              fontSize: 17,
                              fontWeight: FontWeight.w500,
                              color: hexToColor(
                                  widget.styles.first.attributes.fontColor),
                            ),
                            textAlign: TextAlign.center,
                          ),
                        ),
                      ],
                    ),
                    SizedBox(
                      height: 12,
                    ),
                  ],
                )
              : Container(),
          ClipRRect(
            borderRadius: BorderRadius.circular(16.0),
            child: RotatedBox(
              quarterTurns: 0,
              child: Container(
                height: 200,
                child: chewieController != null &&
                        chewieController.videoPlayerController.value.initialized
                    ? Chewie(
                        controller: chewieController,
                      )
                    : Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: [
                          SpinKitFadingCircle(
                            color: Colors.black,
                          ),
                        ],
                      ),
              ),
            ),
          ),
          widget.mineral.properties.first.caption != null &&
                  widget.mineral.properties.first.caption != ""
              ? Column(
                  children: [
                    SizedBox(
                      height: 12,
                    ),
                    Text(
                      widget.mineral.properties.first.caption,
                      style: TextStyle(
                        fontSize: 17,
                        fontWeight: FontWeight.w500,
                        color: getFontColor(),
                      ),
                      overflow: TextOverflow.ellipsis,
                      textAlign: TextAlign.center,
                      maxLines: 2,
                    ),
                  ],
                )
              : Container(),
          Padding(
            padding: const EdgeInsets.only(top: 10.0),
            child: widget.mineral.properties.first.content != null
                ? Column(
                    children: [
                      Html(
                          data: widget.mineral.properties.first.content,
                          style: {
                            "html": HtmlStyle.Style(
                                fontSize: HtmlStyle.FontSize.large,
                                color: getFontColor()),
                            "p": HtmlStyle.Style(
                              lineHeight: 1,
                              display: HtmlStyle.Display.BLOCK,
                              margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
                            ),
                          }),
                    ],
                  )
                : Container(),
          )
        ],
      ),
    );
  }
}

提前致谢!

终于在经过大约一周的努力后发现了问题,问题是因为在父小部件的 AppBar 中我使用了 PreferedSize 并为其内部的元素提供了一些填充,因为播放器是在它上面渲染的并且因为 appBar 它无法进入全屏,所以它会处理控制器。 解决方法是检查子窗口小部件内部是否有 VideoPlayer,忽略填充,效果很好。