相对于其他 Widget 更改 size/position 文本

Change size/position of Text relative to other Widget

有人能帮忙吗?

目前,我在视频上显示的文本具有固定的大小和位置。

我想知道如何更改此 dynamically/responsively 以匹配其父窗口小部件(视频)的大小。

我尝试了一种使用 GlobalKey 的方法,但出现错误,我认为这是因为视频尚未加载..

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      drawer: ResponsiveLayout.isSmallScreen(context) ? NavDrawer() : null,
      body: Container(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              NavBar(),
              Body(),
              Footer(),
            ],
          ),
        ),
      ),
    );
  }
}

class Body extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ResponsiveLayout(
      largeScreen: LargeScreen(),
      mediumScreen: LargeScreen(),
      smallScreen: LargeScreen(),
    );
  }
}

class LargeScreen extends StatefulWidget {
  @override
  _LargeScreenState createState() => _LargeScreenState();
}

class _LargeScreenState extends State<LargeScreen> {
  VideoPlayerController _videoPlayerController;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    _videoPlayerController = VideoPlayerController.asset(
      'assets/videos/video.mp4',
    );
    _initializeVideoPlayerFuture = _videoPlayerController.initialize();

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 40),
      child: Column(
        children: <Widget>[
          FutureBuilder(
            future: _initializeVideoPlayerFuture,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done &&
                  !_videoPlayerController.value.isBuffering) {
                // If the VideoPlayerController has finished initialization, use
                // the data it provides to limit the aspect ratio of the VideoPlayer.
                return AspectRatio(
                  aspectRatio: _videoPlayerController.value.aspectRatio,
                  // Use the VideoPlayer widget to display the video.
                  child: Stack(
                    children: <Widget>[
                      VideoPlayer(_videoPlayerController),
                      Positioned(
                        bottom: 20,
                        left: 20,
                        child: FittedBox(
                          child: Text(
                            'Text over\na video',
                            style: TextStyle(
                                color: Colors.white,
                                fontSize:50),
                          ),
                        ),
                      )
                    ],
                  ),
                );
              } else {
                // If the VideoPlayerController is still initializing, show a
                // loading spinner.
                return Center(child: CircularProgressIndicator());
              }
            },
          ),
        ],
      ),
    );
  }

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

可通过 MediaQuery.of(context).size (Documentation) 轻松访问。

请记住,您必须在构建方法内部调用,因为它需要上下文

LayoutBuilder 可以为您提供 widthheight 属性,对应于当前可用的 space。检查此文档 here. It provides the builder with a BoxConstraints instance as in here。您可以使用此信息调整文本大小。

检查 Align widget。它可以将子组件放置在父组件坐标系中的特定位置。在您的情况下,它将位于 Stack 小部件的坐标上。

我会尝试下面的方法。

  1. Text 小部件包裹在 Align 小部件中,并使用 FractionalOffset 对齐小部件。您也可以直接使用 Alignment 实例。两种方法的起源都会有所不同。检查文档 here
  2. 然后将我的 Align 小部件包裹在 LayoutBuilder 小部件中以获得可用大小并根据它确定我的字体大小。类似于 fontSize: constraints.maxWidth / 25

下面是示例工作代码。

// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      // drawer: ResponsiveLayout.isSmallScreen(context) ? NavDrawer() : null,
      body: Container(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              // NavBar(),
              Body(),
              // Footer(),
            ],
          ),
        ),
      ),
    );
  }
}

class Body extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // return ResponsiveLayout(
    //   largeScreen: LargeScreen(),
    //   mediumScreen: LargeScreen(),
    //   smallScreen: LargeScreen(),
    // );
    return LargeScreen();
  }
}

class LargeScreen extends StatefulWidget {
  @override
  _LargeScreenState createState() => _LargeScreenState();
}

class _LargeScreenState extends State<LargeScreen> {
  VideoPlayerController _videoPlayerController;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    _videoPlayerController = VideoPlayerController.network(
      'http://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4',
    );
    _initializeVideoPlayerFuture =
        _videoPlayerController.initialize().then((onValue) {
      setState(() {});
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 40),
      child: Column(
        children: <Widget>[
          FutureBuilder(
            future: _initializeVideoPlayerFuture,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done &&
                  !_videoPlayerController.value.isBuffering) {
                // If the VideoPlayerController has finished initialization, use
                // the data it provides to limit the aspect ratio of the VideoPlayer.
                return AspectRatio(
                  aspectRatio: _videoPlayerController.value.aspectRatio,
                  // Use the VideoPlayer widget to display the video.
                  child: Stack(
                    children: <Widget>[
                      VideoPlayer(_videoPlayerController),
                      LayoutBuilder(
                        builder: (context, constraints) {
                          return Align(
                            // this decides the position of the text.
                            alignment: FractionalOffset(0.05, 0.95),
                            child: FittedBox(
                              child: Text(
                                'Text over\na video',
                                style: TextStyle(
                                  color: Colors.white,
                                  // here font size is ratio of the maxwidth available for this widget.
                                  fontSize: constraints.maxWidth / 25,
                                ),
                              ),
                            ),
                          );
                        },
                      )
                    ],
                  ),
                );
              } else {
                // If the VideoPlayerController is still initializing, show a
                // loading spinner.
                return Center(child: CircularProgressIndicator());
              }
            },
          ),
          FloatingActionButton(
            onPressed: () {
              setState(() {
                _videoPlayerController.value.isPlaying
                    ? _videoPlayerController.pause()
                    : _videoPlayerController.play();
              });
            },
            child: Icon(
              _videoPlayerController.value.isPlaying
                  ? Icons.pause
                  : Icons.play_arrow,
            ),
          ),
        ],
      ),
    );
  }

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