在综合浏览量中使用全局键的问题

时间:2019-07-20 09:31:50

标签: flutter flutter-layout

我的应用程序中有三个级别的小部件(例如)。

更高级别:_HomePage <-------返回PageView小部件

中级:_PlayerPage <-------页面项(容器)

下级:_YoutubePlayer <------- YoutubePlayerFlutter小部件(插件)

综合浏览量可以垂直滚动,并且可以随着用户滚动来切换页面。 YoutubePlayer窗口小部件使用GlobalKey,因此在页面之间滚动和切换的效果非常流畅且快速。但是,这有一个问题。如果用户翻页失败,但仅滚动了一半,使其返回原始位置,则将导致GlobalKey复制错误并弄乱元素的生命周期,因为即使翻页失败,翻页事件仍然会触发,但用户一旦开始拖动,并在卸载前一个元素的生命周期(如其在文档中所述)之前,使用相同的全局密钥创建新的小部件:

  

一个元素只能在当前动画帧结束之前保持不活动状态。在动画帧的末尾,所有仍处于非活动状态的元素都将被卸载。

在解决问题之后,我尝试了一些可能的解决方法,我认为它可以解决问题:

  1. 不使用全局密钥。

  2. 使用全局键,但是创建一个自定义ScrollPhysics以防止用户按住或缓慢拖动页面。用户只能翻页。

。 。 结果: 1.如果我不使用全局密钥,它可以很好地工作而不会引发任何错误,但是整体性能会变慢,因此,这会导致另一个问题。如果快速重复滑动,则视频加载时间无法赶上滑动速度。因此,某些视频在加载时会出错(但不会破坏整个应用程序,只会破坏视频本身)。此外,由于有全局键,因此滑动手势本身也无法正常工作。我也尝试过使用UniqueKey,但是与完全不使用键似乎没有什么不同。

结论:与在性能方面不使用全局密钥相比,我认为使用全局密钥更好。

  1. 我尝试修改minFlingVelocity和DragStartDistanceMotionThreshold。网页浏览量滚动物理学似乎正在使用两种独立的方式来翻页:拖动和滑动。因此事实证明,调整击打速度并不是我想要的。但是,当我将DragStartDistanceMotionThreshold设置为设备屏幕的高度时,它可以通过缓慢的拖动来禁用移动页面,但是按我的意愿仍然可以运行。但是出现了其他问题, 1)翻转不会反向(在我的情况下为向上),因此无法返回上一页。 2)某种程度上的猛击不会在两次猛击之间没有延迟(大约1秒)的情况下重复进行。因此,我必须喜欢一次猛扑,然后休息1秒,再一次猛扑。除此之外,这不是良好的用户体验,如果用户继续尝试反复刷新,仍然会导致Globalkey复制错误。

结论:仅当有两个问题(禁用反向弹射和重复弹射)的解决方案时,这才可能是最佳解决方案,但我找不到解决办法。

如果您还有其他解决方法的建议或解决方案,请告诉我。我很感激。 我的简化代码如下:

import 'dart:math';
import 'package:JustMusic/global_components/api.dart';
import 'package:JustMusic/routes/home/components/youtube_player.dart';
import 'package:JustMusic/utils/custom_scroll_physics.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  ScrollPhysics _pageViewScrollPhysics = new CustomScrollPhysics();
  final _pageController = PageController(initialPage: 0);
  PageView pageView;
  List<dynamic> _sources = [];
  int _previousPageIndex = 0;
  var _futureVideo;

  @override
  void initState() {
    _futureVideo = Api.getVideoList();
    _futureVideo.then((videos) {
      _sources = videos;
      pageView = PageView(
          physics: _pageViewScrollPhysics,
          controller: _pageController,
          scrollDirection: Axis.vertical,
          onPageChanged: (index) {
            if (index > _previousPageIndex) {
              print('page switched to $index (down)');
            } else {
              print('page switched to $index (up)');
            }
            _previousPageIndex = index;
          },
          children: []..addAll(_sources.map((_source) {
                return YoutubePlayerScreen(
                    source: _source, pageController: _pageController);
            })));
    });
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: _futureVideo,
        builder: (BuildContext context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            return pageView;
          } else if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else {
            return Center(
              Text('Error: ${snapshot.error}'),
            );
          }
        });
  }
}

import 'package:flutter/material.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';

class YoutubePlayerScreen extends StatefulWidget {
  YoutubePlayerScreen({
    @required this.source,
    @required this.pageController
  });

  final PageController pageController;
  final dynamic source;

  State<YoutubePlayerScreen> createState() => _YoutubePlayerScreenState();
}

class _YoutubePlayerScreenState extends State<YoutubePlayerScreen> {
  var _controller = YoutubePlayerController();

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
          child: YoutubePlayer(
            context: context,
            videoId: YoutubePlayer.convertUrlToId(widget.source["videoUrl"]),
            flags: YoutubePlayerFlags(
              disableDragSeek: true,
              autoPlay: false,
              mute: false,
              showVideoProgressIndicator: true,
            ),
            videoProgressIndicatorColor: Colors.amber,
            progressColors: ProgressColors(
              playedColor: Colors.amber,
              handleColor: Colors.amberAccent,
            ),
            onPlayerInitialized: (controller) {
              _controller = controller;
              _controller.cue();
              _controller.addListener(() {
                if (_controller.value.playerState == PlayerState.CUED) {
                  _controller.play();
                }
              }
            );
          }
        )
      )
    );
  }
}

您可以从此处找到YoutubePlayerFlutter的源代码: https://github.com/sarbagyastha/youtube_player_flutter/blob/master/lib/src/youtube_player.dart


编辑:  我还想出了另一种解决方法,但不知道如何实现。它仅在onPageChanged上加载YoutubePlayerWidget。因为我已经测试了拖动页面会加载上一个/下一个视频,但是不会触发onPageChanged侦听器。仅当页面实际转到上一页/下一页时,才会触发侦听器。

0 个答案:

没有答案