Hannes Hultergård
Hannes Hultergård

Reputation: 1207

Using BuildContext outside build function

I have a function that builds a widget to be able to reuse it, and in that function I want to set the text theme. My problem is that to do that I need to access the BuildContext to do so. The only way I can think of is to pass it as a parameter in every function call, but it feels like there must be a simpler method. Or is this the best way to do it?

Here is the current code:

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

import 'package:snapping_page_scroll/snapping_page_scroll.dart';

void main() => runApp(MaterialApp(
      theme: ThemeData(
        backgroundColor: Color(0xff121217),
         textTheme: TextTheme(
           headline: TextStyle(fontSize: 40)
         )
      ),
      home: SplashScreen(),
    ));

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();
    loadData();
  }

  //Simulates loading of data
  Future<Timer> loadData() async {
    return new Timer(Duration(seconds: 1), onDoneLoading);
  }

  onDoneLoading() async {
    Navigator.of(context).push(MaterialPageRoute(builder: (context) => Home()));
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Color(0xff121217),
      child: Padding(
        padding: const EdgeInsets.all(20),
        child: Image.asset('assets/logo.png'),
      ),
    );
  }
}

class Home extends StatelessWidget {

  Widget page(text, color, context){
    return Container(
      color: color,
      child: Align(
        alignment: Alignment(0, 0.5),
        child: Text(text, style: Theme.of(context).textTheme.headline,),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: SnappingPageScroll(
          children: <Widget>[
            page('Page 1', Colors.orange, context),
            page('Page 2', Colors.green, context),
          ],
        ),
      ),
    );
  }
}

Upvotes: 13

Views: 17627

Answers (6)

McGuy
McGuy

Reputation: 89

Wrap the function with a Builder, and you will have access to the BuildContext.

Upvotes: -1

Louise
Louise

Reputation: 41

The Theme is usually an object that could be accessed from everywhere in your code to maintain uniform UI and consistency.

Assuming you have different themes for different parts of your app (via nested Navigators, etc.), I believe that's the only time where you need the widget's BuildContext to find the Theme it's located under. In that case, I agree with Filip's answer about using a Builder widget.

I like to share another way to go about it is by using GlobalKeys, supplying it to a nested Navigator widget, and accessing declared key in the function. This is for those that need extra assurance that they're using the right theme. But in most cases (probably all), Flutter should be able to detect the right Theme which the BuildContext is under.

Upvotes: 0

Define a variable from the BuildContext class at the top (for example, its name is a). Sync variable a to context under build function You can use variable a anywhere you want.

Upvotes: 1

Lojith Vinsuka
Lojith Vinsuka

Reputation: 1051

Convert stateless widget to a stateful widget :)

enter image description here

enter image description here

Errors gone :) enter image description here

Upvotes: 1

lazos
lazos

Reputation: 1075

You have access to BuildContext inside build method.

So you can move your place() function inside build.

Widget build(BuildContext context) {
  page(text, color) {
    return Container(
      color: color,
      child: Align(
        alignment: Alignment(0, 0.5),
        child: Text(
          text,
          style: Theme.of(context).textTheme.headline,
        ),
      ),
    );
  }

  return MaterialApp(
    home: Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          page('Page 1', Colors.orange),
          page('Page 2', Colors.green),
        ],
      ),
    ),
  );
}

Also in cases like yours a good pattern would be to create your own reusable Page widget and pass your parameters via constructor.

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Column(
          children: <Widget>[
            _Page(text: 'Page 1', color: Colors.orange),
            _Page(text: 'Page 2', color: Colors.green),
          ],
        ),
      ),
    );
  }
}

class _Page extends StatelessWidget {
  const _Page({
    Key key,
    @required this.color,
    @required this.text,
  }) : super(key: key);

  final Color color;
  final String text;
  @override
  Widget build(BuildContext context) {
    return Container(
      color: color,
      child: Align(
        alignment: Alignment(0, 0.5),
        child: Text(
          text,
          style: Theme.of(context).textTheme.headline,
        ),
      ),
    );
  }
}

Upvotes: 3

Filip P.
Filip P.

Reputation: 1354

You can use builder widget. ... https://api.flutter.dev/flutter/widgets/Builder-class.html

Upvotes: 8

Related Questions