Chris
Chris

Reputation: 2034

Change size/position of Text relative to other Widget

Can anyone help?

Currently, the Text that I am displaying over a video has a fixed size and position.

I'm wondering how I can change this dynamically/responsively to match the size of its parent widget (the Video).

I tried a method using a GlobalKey but got an error, I think it's because the video hadn't loaded..

text over a video

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();
  }
}

Upvotes: 1

Views: 966

Answers (2)

Abhilash Chandran
Abhilash Chandran

Reputation: 7509

LayoutBuilder can provide you with width and height properties which corresponds to the currently available space. Check this documentation here. It provides the builder with a BoxConstraints instance as in here. You can use this information to size your text.

Check the Align widget. It can place the child on specific location within the parent widget's coordinate system. In your case it will be on the coordinates of the Stack widget.

I would try something like the following.

  1. Wrap the Text widget inside a Align widget and use FractionalOffset to place align the widget. You can directly use the Alignment instance also. The origin will vary vary for both the approach. Check the docs here
  2. Then Wrap my Align widget inside a LayoutBuilder widget to get the available size and decide my font size based on it. Something like fontSize: constraints.maxWidth / 25

Below is sample working code.

// 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();
  }
}

Upvotes: 1

Tizianoreica
Tizianoreica

Reputation: 2236

It's easily accessible via MediaQuery.of(context).size (Documentation).

Remember that you have to call inside your build method since it demands the context

Upvotes: 0

Related Questions