Asghar Ali Hazara
Asghar Ali Hazara

Reputation: 13

How to access ThemeData from imported widgets

I can not use the ThemeData from the imported custom Widgets that I have imported from other files, I dont know if the BuildContext is changing or what. To all the widgets that are used in the main.dart file they can easily use Theme.of(context).colorScheme.primary but from imported widgets this does not work.

main.dart

import 'package:flutter/material.dart';

import 'widgets/expenses_list.dart';
import 'models/expenses_model.dart';
import 'widgets/new_expense.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData().copyWith(
        colorScheme: ThemeData().colorScheme.copyWith(primary: Colors.red),
      ),
      home: MyAppPage(),
    );
  }
}

class MyAppPage extends StatefulWidget {
  @override
  _MyAppPageState createState() => _MyAppPageState();
}

class _MyAppPageState extends State<MyAppPage> {
  final List<ExpensesModel> _expensesObjectList = [
    ExpensesModel(
      id: DateTime.now().toString(),
      name: "Shoes",
      amount: 1200,
      date: DateTime.now(),
    ),
    ExpensesModel(
      id: DateTime.now().toString(),
      name: "Gun",
      amount: 120000,
      date: DateTime.now(),
    ),
  ];

  void _addExpense(String exTitle, double exAmount) {
    final _addExpenseObject = ExpensesModel(
      id: DateTime.now().toString(),
      name: exTitle,
      amount: exAmount,
      date: DateTime.now(),
    );
    setState(() {
      _expensesObjectList.add(_addExpenseObject);
    });
  }

  void _startAddNewExpense(BuildContext context) {
    showModalBottomSheet(
        context: context,
        builder: (bcontext) {
          return NewExpense(_addExpense);
        });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.primary,
          // HERE IT DOES WORK
          title: Text(
            "Expense App",
            // style: Theme.of(context).textTheme.title,
          ),
          actions: [
            IconButton(
              onPressed: () {
                _startAddNewExpense(context);
              },
              icon: Icon(Icons.add),
            ),
          ],
        ),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Card(
              elevation: 5,
              color: Theme.of(context).colorScheme.primary,
              // HERE IT DOES WORK
              child: Text("CHART!!"),
            ),
            ExpensesList(_expensesObjectList), //THE IMPORTED WIDGET
          ],
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            _startAddNewExpense(context);
          },
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

imported widget

import 'package:flutter/material.dart';

import '../models/expenses_model.dart';

class ExpensesList extends StatelessWidget {
  final List<ExpensesModel> expensesObjectList;

  ExpensesList(this.expensesObjectList);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 600,
      child: ListView.builder(
        itemBuilder: (context, index) {
          return Card(
            elevation: 5,
            child: Row(
              children: [
                Container(
                  padding: EdgeInsets.symmetric(
                    vertical: 10,
                    horizontal: 10,
                  ),
                  margin: EdgeInsets.all(10),
                  decoration: BoxDecoration(
                    border: Border.all(
                      color: Theme.of(context).colorScheme.primary,
                      // HERE IT DOES NOT WORK
                      width: 2,
                    ),
                  ),
                  child: Text(
                    "PKR ${expensesObjectList[index].amount}",
                    style: TextStyle(
                      color: Theme.of(context).colorScheme.primary,
                      // HERE IT DOES NOT WORK
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      "${expensesObjectList[index].name}",
                      style:
                          TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                    ),
                    Text(
                      DateTime.now().toString(),
                      style: TextStyle(
                        color: Colors.grey,
                      ),
                    ),
                  ],
                ),
              ],
            ),
          );
        },
        itemCount: expensesObjectList.length,
      ),
    );
  }
}

Screenshot of the app

as you can see the border and text aren't using the theme-defined color which is red.

Upvotes: 1

Views: 1142

Answers (2)

Yuu Woods
Yuu Woods

Reputation: 1348

I think unnecessary "MaterialApp" of "build" in "class _MyAppPageState", like this.

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      backgroundColor: Theme.of(context).colorScheme.primary,
      // HERE IT DOES WORK
      title: Text(
        "Expense App",
        // style: Theme.of(context).textTheme.title,
      ),
      actions: [
        IconButton(
          onPressed: () {
            _startAddNewExpense(context);
          },
          icon: Icon(Icons.add),
        ),
      ],
    ),
    body: Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Card(
          elevation: 5,
          color: Theme.of(context).colorScheme.primary,
          // HERE IT DOES WORK
          child: Text("CHART!!"),
        ),
        ExpensesList(_expensesObjectList), //THE IMPORTED WIDGET
      ],
    ),
    floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    floatingActionButton: FloatingActionButton(
      onPressed: () {
        _startAddNewExpense(context);
      },
      child: Icon(Icons.add),
    ),
  );
}

If you really need to "MaterialApp" of "class _MyAppPageState", I think you can add theme property, like this.

@override
Widget build(BuildContext context) {
  return MaterialApp(
    debugShowCheckedModeBanner: false,
    theme: Theme.of(context), // <- add this line.
    home: Scaffold(

By the way, why won't you use primarySwatch?
How about this?

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: MyAppPage(),
    );
  }
}

enter image description here

Upvotes: 0

Dc7
Dc7

Reputation: 1579

You can access the ThemeData of your app by following.

Color color = Theme.of(context).primaryColor;

Upvotes: 0

Related Questions