How to change the textTheme in the ThemeData class? - flutter

I cannot change the color of the TextTheme property in the ThemeData class even though the code doesn't give any error.
Here is what I have done so far:
import 'package:flutter/material.dart';
void main() => runApp(BMICalculator());
class BMICalculator extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
appBarTheme: AppBarTheme(
backgroundColor: Color(0xff0a0e21),
),
scaffoldBackgroundColor: Color(0xff0a0e21),
textTheme: TextTheme(bodyText1: TextStyle(color: Colors.blue)),//the text remains white in the app.
),
home: InputPage(),
);
}
}
class InputPage extends StatefulWidget {
#override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Center(
child: Text('Body Text'),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => print('object'),
),
);
}
}
What am I doing wrong?

You have declared the themes successfully, but are not using it. Here is the replacement code snippet:
body: Center(
child: Text('Body Text', style: Theme.of(context).textTheme.bodyText1),
)
You need to specify the theme in style attribute for the necessary changes to take place.

Try passing textTheme: ThemeData value
here is an example for textTheme
textTheme: ThemeData.light().textTheme.copyWith(
headline6: TextStyle(
fontFamily: 'OpenSans',
fontSize: 18,
fontWeight: FontWeight.bold,
),
Just match your implementation with mine, here I have implemented textTheme for titles.
now if I want to refer to this headline6 theme I can do
Theme.of(context).textTheme.headline6

As much as I know there are a-lot of different properties in TextTheme class, such as bodytext1, bodytext2, headline1, headline2, caption etc etc...
And you can configure many of them to use them later, but there is no catalog or confirmation that which part of the app it will be applied to, i.e. Out of all the places that uses the text widget, to which bodytext1 will be applied to it is not known...but overtime you will get the feel for it.
But for now you have to call it manually where-ever you want to use that specific text configuration, such as in your code you have to do it like:
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Center(
child: Text('Body Text', style: Theme.of(context).textTheme.bodyText1,),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => print('object'),
),
);
The main point of adding theme is code-reusability and making it dynamic which is obviously achieved by this too.

Related

Not getting the scaffold context in flutter custom app bar

I have written this flutter widget which I wanted to implement a custom app bar along with a drawer. Here is my starting widget
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Food App',
theme: ThemeData(
primaryColor: kPrimaryColor,
scaffoldBackgroundColor: Colors.white,
),
home: Scaffold(
bottomNavigationBar: BottomNavBar(),
body: HomeScreen(),
drawer: CustomDrawer(),
appBar: homeAppBar(context, (context) {
Scaffold.of(context).openDrawer();
}),
));
}
}
I have implemented a callback in the app bar icon button
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:food_app/constants.dart';
AppBar homeAppBar(BuildContext context, Function function) {
return AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: SvgPicture.asset("assets/icons/menu.svg"),
onPressed: () {
function(context);
},
),
title: RichText(
text: TextSpan(
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: "Makana",
style: TextStyle(color: ksecondaryColor),
),
TextSpan(
text: "Food",
style: TextStyle(color: kPrimaryColor),
),
],
),
),
actions: <Widget>[
IconButton(
icon: SvgPicture.asset("assets/icons/notification.svg"),
onPressed: () {},
),
],
);
}
It gives me an error
════════ Exception caught by gesture ═══════════════════════════════════════════
The following assertion was thrown while handling a gesture:
Scaffold.of() called with a context that does not contain a Scaffold.
No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This usually happens when the context provided is from the same StatefulWidget as that whose build function actually creates the Scaffold widget being sought.
There are several ways to avoid this problem. The simplest is to use a Builder to get a context that is "under" the Scaffold. For an example of this, please see the documentation for Scaffold.of():
https://api.flutter.dev/flutter/material/Scaffold/of.html
A more efficient solution is to split your build function into several widgets. This introduces a new context from which you can obtain the Scaffold. In this solution, you would have an outer widget that creates the Scaffold populated by instances of your new inner widgets, and then in these inner widgets you would use Scaffold.of().
A less elegant but more expedient solution is assign a GlobalKey to the Scaffold, then use the key.currentState property to obtain the ScaffoldState rather than using the Scaffold.of() function.
The context used was: MyApp
When the exception was thrown, this was the stack
I have tried it like this also
AppBar homeAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: SvgPicture.asset("assets/icons/menu.svg"),
onPressed: () {
Scaffold.of(context).openDrawer();
},
),
title: RichText(
text: TextSpan(
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: "Makana",
style: TextStyle(color: ksecondaryColor),
),
TextSpan(
text: "Food",
style: TextStyle(color: kPrimaryColor),
),
],
),
),
actions: <Widget>[
IconButton(
icon: SvgPicture.asset("assets/icons/notification.svg"),
onPressed: () {},
),
],
);
}
Though it is under the scaffold from the main.dart, it still throws the same error. I tried Builder in app bar but it is not acceptable in AppBar return type. I am a new bee into the flutter world. Please help!
The problem is that the context that you are passing to the homeAppBar function does not have access to a Scaffold.
#override
// The following context that is the one that you are passing to the function is above the scaffold and hence does not finds any scaffold "above" it.
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Food App',
theme: ThemeData(
primaryColor: kPrimaryColor,
scaffoldBackgroundColor: Colors.white,
),
home: Scaffold(
bottomNavigationBar: BottomNavBar(),
body: HomeScreen(),
drawer: CustomDrawer(),
appBar: homeAppBar(context, (context) {
There are two solutions either wrap the homeAppBar inside a Builder like follows:
Builder(builder: (ctx)=>homeAppBar(ctx),)
Or just instead of using a function refactor the widget to use a class which is the one I would recommend for optimization reasons see this answer for a thorough explanation.

How to set input text color when defining a theme?

I define my theme as follows:
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: bgColor,
textTheme: GoogleFonts.poppinsTextTheme(Theme.of(context).textTheme)
.apply(bodyColor: Colors.white),
canvasColor: secondaryColor,
),
How can I also change the color of text in TextFields? Do I have to modify the copyWith() call somehow?
Edit: I think I have a special case, because I'm using Flutter Login, I'm not sure if that changes things.
TextFields use subtitle1 text style by default, so the first way to change text color is to set subtitle1's style:
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
subtitle1: TextStyle(color: Colors.pink),
),
),
home: HomePage(),
);
}
}
You can also specify style overrides directly from TextField's style parameter:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
style: TextStyle(color: Colors.orange),
),
),
],
),
],
),
);
}
}
I tried Your code and it works fine for me:
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: Colors.grey[900],
textTheme: GoogleFonts.poppinsTextTheme()
.apply(bodyColor: Colors.white)
.copyWith(subtitle1: TextStyle(color: Colors.purple)),
canvasColor: Colors.grey[800],
),
home: HomePage(),
);
}
In terms of performance, copyWith is a lot lighter than apply because it doesn't have to recreate all styles.

How do I adjust the margin for Flutter AppBar?

How do I customize the app bar such that the back button is not so close to the border? I want to achieve this for all pages.
I can't seem to set margins for the app bar.
Reference to the back button close to border
Here are my codes
// General Theme
AppBarTheme(
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
backgroundColor: Colors.transparent,
elevation: 0,
textTheme: TextTheme(
headline6: TextStyle(
color: kTextColor,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
);
// Individual Screen
import 'package:flutter/material.dart';
import 'components/body.dart';
class SplashScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello'),
),
body: Body(),
);
}
}
You may have to create your own custom widget for this, your custom widget can be a Row widget with multiples child.
Also, checkout SafeArea widget.
class SplashScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: MyCustomWidget(title: 'Hello'),
),
body: Body(),
);
}
}

Flutter back button is hidden on navigation

Why MaterialApp hides back button from AppBar for my new screen. I have many screens in my app, where I need to use ThemeData. To do that, I use MaterialApp in another screen, but I don't see any back arrow on the AppBar().
return MaterialApp(
theme: ThemeData(
fontFamily: 'IranSansLight',
textTheme: TextTheme(
headline: TextStyle(fontSize: 72.0, fontWeight: FontWeight.bold, fontFamily: 'IranSansLight'),
title: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic, fontFamily: 'IranSansLight'),
body1: Theme.of(context).textTheme.caption.copyWith(fontFamily: 'IranSansLight', color: Colors.black)),
),
home: ScopedModel(
model: CounterModel(),
child: Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(automaticallyImplyLeading:true,title: Text('aaaa'),),
body: Container(
)),
),
),
);
}
You are using MaterialApp for all individual screens, this is not the correct way, all you need is just one MaterialApp for the entire app.
void main() {
runApp(
MaterialApp(home: HomePage()), // MaterialApp widget should be used only here
);
}
And whenever you need to use Theme in your 2nd screen, use something like:
#override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
// override whatever you need like
textTheme: TextTheme(...),
),
child: Scaffold(),
);
}

Flutter Text Color Theme doesn't work under ListTile title

I am getting started in Flutter and just trying out stuff.
I set a custom theme, but Text Widgets under the title property of ListTile don't get the right color. Also Icons under the leading property don't get the right color as well.
I tried setting some other colors, and sorted out, that the Problem only exists within that element.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MyApp',
theme: ThemeData(
primaryColor: Colors.black,
scaffoldBackgroundColor: Color(0xff202020),
cardTheme: CardTheme(color: Colors.black),
textTheme: TextTheme(
body1: TextStyle(color: Colors.white),
subtitle: TextStyle(color: Colors.white),
headline: TextStyle(color: Colors.white)),
iconTheme: IconThemeData(color: Colors.white)),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
HomePageState createState() => new HomePageState();
}
class HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("HomePage"),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
tooltip: "back to the last page.",
onPressed: () {
Navigator.pop(context);
})
),
body: Card(
child: ListTile(
title: Text("Test"),
leading: new Icon(Icons.devices)
),
));
}
}
The Text for the title should appear white as well as the icon, instead it is black. All other Text is white.
The title on ListTile is using subhead textStyle of Theme. So if you want config color of ListTile on ThemeData you need change subhead.
textTheme: TextTheme(
subhead: TextStyle(color: Colors.white),
...)
In order to make use of you're theme you need to use Theme.of(context).
Container(
color: Theme.of(context).accentColor,
child: Text(
'Text with a background color',
style: Theme.of(context).textTheme.title,
),
);
Read more about it here in the cookbook. You are on the right track
https://flutter.dev/docs/cookbook/design/themes
In Flutter 3 which I'm currently using, titleMedium defines the text style for title of ListTiles.
MaterialApp(
theme: ThemeData(
textTheme: Typography().black.copyWith(
titleMedium: const TextStyle(
fontSize: 32,
),
),
)
For example the above theme makes theme relatively large.
Flutter team should provide developers with a reference for these styles. For the moment you can find out which style corresponds to which widget by trial and error.
Just change body1 to bodyText1 in the following location:
C:\src\flutter.pub-cache\hosted\pub.dartlang.org\charts_flutter-0.9.0\lib\src\behaviors\legend\legend_entry_layout
This will solve the issue.