1

我有一个主屏幕小部件,它使用 video_player 包播放全屏背景视频。这段代码对我来说很好:

class HomeScreen extends StatefulWidget {
  HomeScreen({Key key}) : super(key: key);

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

class _HomeScreenState extends State<HomeScreen> {
  VideoPlayerController _controller;

  void initState() {
    super.initState();
    // Pointing the video controller to mylocal asset.
    _controller = VideoPlayerController.asset("assets/waterfall.mp4");

    _controller.initialize().then((_) {
      // Once the video has been loaded we play the video and set looping to true.
      _controller.play();
      _controller.setLooping(true);
      // Ensure the first frame is shown after the video is initialized.
      setState(() {});
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Stack(
          children: <Widget>[
            SizedBox.expand(
              child: FittedBox(
                // If your background video doesn't look right, try changing the BoxFit property.
                // BoxFit.fill created the look I was going for.
                fit: BoxFit.fill,
                child: SizedBox(
                  width: _controller.value.size?.width ?? 0,
                  height: _controller.value.size?.height ?? 0,
                  child: VideoPlayer(_controller),
                ),
              ),
            ),
            Container(
              child: Center(
                child: Text('Hello!'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

问题是,如何使用颤振 Hooks 来实现这一点?我知道我必须使用 useEffect() 来实现 initState() 和 dispose()、useFuture() 的功能,也许还有 useMemoized() 来处理异步 _controller.initialize() 调用,还有什么可能?但是,我无法将它们粘合以获得所需的结果。任何人都可以向我指出上述代码的“使用 Hooks”实现吗?

4

1 回答 1

0

当我遇到这个问题时,我正在寻找如何将 VideoPlayer 演示从 StatefulWidget 转换为 HookWidget 的答案。我想出了一些可行的方法,因此我将其发布在这里,因为在其他地方我找不到任何东西,而其他一些人正在访问此页面以寻找答案。

我使用了视图模型。视频控制器是视图模型的属性。由于某些控件不包括在内,此代码将无法编译。但它将演示视图模型的结构和合并。

这是小部件文件:

import 'package:flutter/foundation.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:video_player/video_player.dart';

import 'intro_viewmodel.dart';

class IntroPage extends HookWidget {
  Future<void> saveAndGetStarted(BuildContext context) async {
    final IntroViewModel introViewModel = context.read(introViewModelProvider);
    await introViewModel.completeIntro();
  }

  Future<void> onNext(BuildContext context) async {
    final IntroViewModel introViewModel = context.read(introViewModelProvider);
    await introViewModel.incrementIntro();
  }

  final List<SliderModel> slides = [
    SliderModel(
        description: 'A word with you before you get started.\n',
        title: 'Why This App?',
        localImageSrc: 'media/Screen1-Movingforward-pana.svg',
        backgroundColor: Colors.lightGray),
    SliderModel(
        description: 'This information will help the app be more accurate\n',
        title: 'Personal Profile',
        localImageSrc: 'media/Screen2-Teaching-cuate.svg',
        backgroundColor: Colors.lightGray)
  ];

  @override
  Widget build(BuildContext context) {
    final IntroViewModel introViewModel = context.read(introViewModelProvider);

    return Scaffold(
        body: Padding(
      padding: const EdgeInsets.all(16.0),
      child: Center(
        child: Column(
          children: [
            Text(
              slides[introViewModel.index].description,
              style: Theme.of(context).textTheme.headline5,
              textAlign: TextAlign.center,
            ),
            Expanded(
                child: FractionallySizedBox(
              widthFactor: .98,
              heightFactor: .5,
              child: VideoPlayer(introViewModel.videoController),
            )),
            Align(
              alignment: Alignment.bottomCenter,
              child: CustomRaisedButton(
                onPressed: () {
                  if (introViewModel.index == slides.length - 1) {
                    saveAndGetStarted(context);
                  } else {
                    onNext(context);
                  }
                },
                color: Theme.of(context).accentColor,
                borderRadius: 15,
                height: 50,
                child: Text(
                  introViewModel.index == 0
                      ? 'Continue'
                      : 'Save and Get Started',
                  style: Theme.of(context)
                      .textTheme
                      .headline5
                      .copyWith(color: Colors.white),
                ),
              ),
            ),
          ],
        ),
      ),
    ));
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IterableProperty<SliderModel>('slides', slides));
  }
}

这是视图模型代码

import 'package:flutter/foundation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:video_player/video_player.dart';
import '../top_level_providers.dart';

final introViewModelProvider = ChangeNotifierProvider<IntroViewModel>((ref) {
//this singleton class provides global access to selected variables
  final SharedPreferencesService localSharedPreferencesService =
      ref.watch(sharedPreferencesService);
  return IntroViewModel(localSharedPreferencesService);
});

class IntroViewModel extends ChangeNotifier {
  IntroViewModel(this.localSharedPreferencesService) : super() {
    state = localSharedPreferencesService?.isIntroComplete();

    // Pointing the video controller to my local asset.
    videoController = VideoPlayerController.asset('media/test_search.mp4');

    videoController.initialize().then((_) {
      // Once the video has been loaded we play the video and set looping to true.
      //  not autoplaying yet
//  videoController.play();
      //    videoController.setLooping(true);
    });
  }

  final SharedPreferencesService localSharedPreferencesService;
  VideoPlayerController videoController;
  bool state = false;
  int index = 0;

  Future<void> completeIntro() async {
    await localSharedPreferencesService.setIntroComplete();
    state = true;
    notifyListeners();
  }

  Future<void> incrementIntro() async {
    ++index;
    notifyListeners();
  }

  bool get isIntroComplete => state;
}

于 2021-08-22T18:32:13.587 回答