Использование пакета video_player с Flutter Hooks для воспроизведения фонового полноэкранного видео

У меня есть виджет главного экрана, который воспроизводит полноэкранное фоновое видео с помощью пакета 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!'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Вопрос в том, как это реализовать с помощью флаттер-хуков? Я понимаю, что мне нужно использовать useEffect () для реализации функций initState () и dispose (), useFuture () и, возможно, useMemoized () для обработки асинхронного вызова _controller.initialize () и чего еще? Но я не могу их склеить, чтобы получить желаемый результат. Может ли кто-нибудь указать мне на реализацию вышеуказанного кода "using Hooks"?

1 ответ

Я искал ответ на вопрос, как преобразовать демонстрацию 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;
}

Другие вопросы по тегам