I have a route that I pushed using Navigator. The weird thing about this is that in this new route, all of my Text widget looks like already have a predetermined style of red color, 32-ish font size, console font face, and double yellow underline.
Here's the code:
import 'package:flutter/material.dart';
import 'package:movie_browsers/src/models/item_model.dart';
class MovieDetail extends StatelessWidget {
final MovieModel movieModel;
const MovieDetail({ Key key, this.movieModel }) : super(key: key);
#override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Column(
children: [
Image.network('https://image.tmdb.org/t/p/w185${movieModel.posterPath}', fit: BoxFit.cover),
Text(movieModel.title, style: TextStyle(color: const Color(0xFFFFFFFFF), fontSize: 14),),
Text("testing"),
]
),
);
}
}
And here's the screenshot:
I already apply styles to the "Frozen II" text as I'm trying to wrap my head around the weird style. The "testing" text is the 'plain' Text widget result without any style. Why is this happening?
The previous (main) screen doesn't have this weirdness. All the text are normal (as expected from Text with no styles).
That's because you're not using any Material component. There are many solutions for it, like you can use Scaffold, Material widget etc.
#override
Widget build(BuildContext context) {
return Material( // add this
child: Center(
child: Column(
children: [
Image.network('https://image.tmdb.org/t/p/w185${movieModel.posterPath}', fit: BoxFit.cover),
Text(movieModel.title, style: TextStyle(color: const Color(0xFFFFFFFFF), fontSize: 14),),
Text("testing"),
]
),
),
);
}
Wrap your whole code inside Scaffold,
Scaffold(
body: Center(
child: Column(
children: [
Image.network('https://image.tmdb.org/t/p/w185${movieModel.posterPath}', fit: BoxFit.cover),
Text(movieModel.title, style: TextStyle(color: const Color(0xFFFFFFFFF), fontSize: 14),),
Text("testing"),
]
),
),
);
Use Scaffold widget
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter'),
),
body: Center(
child: Container(
child: Text('Hello World'),
),
),
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter'),
),
body: Center(
child: Container(
child: Text('Hello World'),
),
),
),
);
}
}
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter'),
),
body: Center(
child: Container(
child: Text('Hello World'),
),
),
),
);
Related
Let's say that I want create a Flutter app. In my app I want to create a Row widget with the following children:
AspectRatio(aspectRatio: 1, child: Center(child: Text("I am text!"))
Image.asset("path/to/asset.png") with unknown aspect ratio
I want to display that Row while keeping both aspect ratios intact. How can I do that?
Here is my attempt:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("This is my app")),
body: Container(
child: Row(children: [buildItem1(), buildItem2()]),
),
);
}
Widget buildItem1() {
return AspectRatio(
aspectRatio: 1,
child: Container(
color: Colors.red, child: Center(child: Text("This is my text"))));
}
Widget buildItem2() {
return Image.asset("path/to/my/asset.jpg");
}
}
And this is what being displayed:
I am trying to figure out a way to automatically shrink the row height such that both items would fit the screen.
If I use a fixed hight like that:
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("This is my app")),
body: Container(
height: 300,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [buildItem1(), buildItem2()],
),
),
);
}
...
Than I get the following:
Which is better, but I want to fill the entire width of the screen.
Thanks for anyone who can help!
You can use Expanded on second widget, that will get the avialable space on row. Also for the image use fit: BoxFit.cover(better looks than width).
body: Container(
height: 300,
child: Row(
children: [buildItem1(), Expanded(child: buildItem2())],
),
),
Widget buildItem2() {
return Image.asset(
"assets/images/user.png",
fit: BoxFit.cover,
);
}
Now if you want full screen, I will prefer
Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
color: Colors.red,
child: Center(
child: Text("This is my text"),
)),
),
Expanded(
child: Image.asset(
"assets/images/user.png",
fit: BoxFit.cover,
)),
],
),
Also LayoutBuilder on scaffold's body provide more options. Also check IntrinsicHeight.
You can see a black area around the elevated button in the given image. I want to change it and match it with the background color of the rest of the page which is Colors.grey[350] .
The flow is like this => in the main.dart I am calling the widget onboardingscreen and then displaying it with pageview.builder
The code for Main.Dart
import 'package:my_mythology/Pages/login_page.dart';
import 'package:my_mythology/Pages/on_boarding_screen.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
backgroundColor: Colors.grey,
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
),
home:
Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context,index) =>(
Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)
)
),
),
Row(
children: [
SizedBox( height: 60,
width: 60,
child: ElevatedButton(onPressed: () {},
style: ElevatedButton.styleFrom(shape: CircleBorder(),),
child: SvgPicture.asset("asset/forwardarrow.svg",fit: BoxFit.contain,),)),
],
),
],
),
);
}
}
the code for Onboardingscreen is
// ignore: camel_case_types
class Onboarding_Screen extends StatelessWidget {
final String image, title, description;
const Onboarding_Screen({
Key? key,
required this.description,
required this.image,
required this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey[350],
body: SafeArea(
child: Column(
children: [
Spacer(),
SizedBox(
height: 400,
width: 400,
child: Image.asset(
image,
fit: BoxFit.fill,
)),
Text(title,
style: Theme.of(context).textTheme.headline5!.copyWith(
fontWeight: FontWeight.bold, color: Colors.black)),
Spacer(),
Text(
description,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black54, fontSize: 16),
),
Spacer(),
],
)),
),
);
}
}
``
First add a Scaffold to your screen, then specify a background color.
import 'package:flutter/material.dart';
import 'onboarding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
backgroundColor: Colors.grey,
),
home: Scaffold(
backgroundColor: Colors.grey[350],
body: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index) => (const Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)),
)),
Row(
children: [
SizedBox(
height: 60,
width: 60,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
child: null,
),
),
],
),
],
),
),
);
}
}
Here is the result.
You are using scaffold inside Onboarding_Screen, therefore the outer part is missing material. You dont need to use multiple MaterialApp and use Scaffold on top level as route widget.
Mostly, you will need to follow
MaterialApp(
home: Scaffold (
body: Column(...
If you create second page, means visit using navigator , you need to use Scaffold, but not MaterialApp.
You can directly provide scaffoldBackgroundColor on MaterialApp's theme.
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: Colors.grey[350], /// direct here
),
home: Scaffold(
body: Column(
children: [
Expanded(
Your widget will
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: Colors.grey[350], /// direct here
),
home: Scaffold(
body: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index) => (Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
))),
),
Row(
children: [
SizedBox(
height: 60,
width: 60,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
child: Text("fff")
// SvgPicture.asset(
// "asset/forwardarrow.svg",
// fit: BoxFit.contain,
// ),
)),
],
),
],
),
),
);
}
}
class Onboarding_Screen extends StatelessWidget {
final String image, title, description;
const Onboarding_Screen({
Key? key,
required this.description,
required this.image,
required this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: [
Spacer(),
SizedBox(
height: 400,
width: 400,
child: Image.asset(
image,
fit: BoxFit.fill,
)),
Text(
title,
style: Theme.of(context)
.textTheme
.headline5!
.copyWith(fontWeight: FontWeight.bold, color: Colors.black),
),
Spacer(),
Text(
description,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black54, fontSize: 16),
),
Spacer(),
],
),
);
}
}
This black background is due to the fact that Row widget with ElevatedButton is not wrapped in Scaffold. Try this in this main.dart:
import 'package:my_mythology/Pages/login_page.dart';
import 'package:my_mythology/Pages/on_boarding_screen.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
backgroundColor: Colors.grey,
),
home:
Scaffold(
backgroundColor: Colors.grey[350],
body:Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context,index) =>(
Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)
)
),
),
Row(
children: [
SizedBox( height: 60,
width: 60,
child: ElevatedButton(onPressed: () {},
style: ElevatedButton.styleFrom(shape: CircleBorder(),),
child: SvgPicture.asset("asset/forwardarrow.svg",fit: BoxFit.contain,),)),
],
),
],
),
)
);
}
}
Also in onboarding_screen.dart:
import 'package:flutter/material.dart';
import 'onboarding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index) => (const Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)),
)),
Container(
color: Colors.grey[350],
child: Row(
children: [
SizedBox(
height: 60,
width: 60,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
child: null,
),
),
],
),
),
],
);
}
}```
I was able to display the child widgets in a grid using the GridView widget,
Widgets such as text and GridView widgets together on one screen
How can I display it?
For example
//sign_in_page.dart
class SignInPage extends StatelessWidget {
void _signInAnonymously() async {
final authResult=await FirebaseAuth.instance.signInAnonymously();
print('${authResult.user.uid}');
}
#override
Widget build(BuildContext context) {
List<Widget> list1=[
SizedBox(
width:50.0,
height:50.0,
child:Container(
color:Colors.blue,
),
),
SizedBox(
width:100.0,
height:100.0,
child:Container(
color:Colors.red,
),
),
SizedBox(
width:100.0,
height:100.0,
child:Container(
color:Colors.green,
),
),
SizedBox(
width:100.0,
height:100.0,
child:Container(
color:Colors.yellow,
),
),
];
return Scaffold(
appBar: AppBar(
title: Text('title'),
elevation: 10.0,
),
//body: buildContent(),
body:Column( //←This will give an error.
children: [
Text('Description of this GridView'),
GridView.count(
crossAxisCount: 3,
children: list1
),
],
),
backgroundColor: Colors.grey[300],
);
}
//main.dart
import 'package:flutter/material.dart';
import 'app/sign_in/sign_in_page.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title:'title',
theme:ThemeData(
primarySwatch: Colors.indigo,
),
home:SignInPage(),
);
}
}
I want to display the text and grid view,
but when I try to display it using the Column widget as above,
I get an error.
Is there any suitable widget to use in this situation?
I guess You should wrap Your GridView.count() with an Expanded() to specify the height, like
Expanded(
child: GridView.count()
)
I want to add an image and a text together in a card but I'm not able to do it. I think a row would be used here but not able to implement it. I'm new to flutter and app development so having some troubles. Any help is really appreciated. Also the cards are in GridView(not in ListView).
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'lists.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Just Another App',
home: Home(),
routes: {
"/webview": (_) => WebviewScaffold(
withJavascript: true,
withLocalStorage: true,
url: 'https://www.google.com/',
appBar: AppBar(
title: Text('Browser'),
),
),
},
theme: ThemeData(primaryColor: Colors.black),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final webView = FlutterWebviewPlugin();
#override
void initState() {
super.initState();
webView.close();
}
#override
Widget build(BuildContext context) {
var gridView = GridView.builder(
itemCount: 15,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Card(
elevation: 10,
child: Padding(
padding: const EdgeInsets.all(35),
child: Container(
// child: SizedBox(child: Text('yashjha'),),
// child: Image.asset('lib/images/${images[index]}'),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('lib/images/${images[index]}'),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
),
),
),
),
),
onTap: () {
setState(() {
Navigator.of(context).pushNamed('/webview');
});
},
);
});
return Scaffold(
appBar: AppBar(
title: Text('Just Another App'),
),
body: Container(
child: gridView,
padding: EdgeInsets.all(12),
),
);
}
[GridViewApp Screenshot][1]}
This is a variable which I'm using in the "body" of Scaffold.
If you want to place an Image and a text side by side, add a Row widget:
child: Row(
children: <Widget>[
DecorationImage(...),
Text(...),
],
)
You can also set mainAxisAlignment and crossAxisAlignment to make sure that your widgets are placed correctly
just wrap your Container into a Row Widget and add a text to it.
Row(
children: <Widget>[
Text("add text here"),
Container(
// child: SizedBox(child: Text('yashjha'),),
// child: Image.asset('lib/images/${images[index]}'),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('lib/images/${images[index]}'),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
),
),
),
],
),
I want to open a drawer after pushing on the custom button in BottomMenu I have trouble with Scaffold.of(context).openDrawer(), it doesn't work. My BottomMenu is a separate widget class. As I understand, it doesn't work because it's a separate context. How can I get the right context? Or perhaps someone knows another solution.
Here my code reproducer:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Drawer'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
bottomNavigationBar: BottomMenu(),
endDrawer: SizedBox(
width: double.infinity,
child: Drawer(
elevation: 16,
child: Container(
color: Colors.black,
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
],
),
),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Call Drawer form menu reproducer',
)
],
),
),
);
}
}
class BottomMenu extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Wrap(
alignment: WrapAlignment.center,
children: <Widget>[
Divider(color: Colors.black, height: 1),
Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
InkWell(
borderRadius: new BorderRadius.circular(20.0),
customBorder: Border.all(color: Colors.black),
child: Container(
padding: EdgeInsets.only(
left: 3, right: 6, bottom: 15, top: 11),
child: Row(
children: <Widget>[
Icon(Icons.menu),
Text('Show menu', style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)),
],
),
),
onTap: () {
Scaffold.of(context).openDrawer();
},
),
],
),
),
],
),
);
}
}
In my case, this worked.
return Scaffold(
key: _scaffoldKey,
endDrawerEnableOpenDragGesture: false, // This!
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.white),
leading: IconButton(
icon: Icon(Icons.menu, size: 36),
onPressed: () => _scaffoldKey.currentState.openDrawer(), // And this!
),
),
drawer: DrawerHome(),
....
and _scaffoldKey must be initialized as,
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
under the class.
The problem is that you specified endDrawer on Scaffold yet you're calling Scaffold.of(context).openDrawer().
openDrawer() documentation states:
If the scaffold has a non-null Scaffold.drawer, this function will cause the drawer to begin its entrance animation.
Since your drawer is null, nothing happens.
In contrast, openEndDrawer() informs us:
If the scaffold has a non-null Scaffold.endDrawer, this function will cause the end side drawer to begin its entrance animation.
Since your endDrawer is not null you should use openEndDrawer() method. Alternatively, if you don't care which side the drawer slides in from, you can use drawer instead of endDrawer when building Scaffold.
My problem solved that instead of
Scaffold.of(context).openEndDrawer()
I give key to Scaffold and then I call by state like below
_scaffoldkey.currentState.openEndDrawer()
It solved my problem I hope It also works for you
Scaffold.of(context).openEndDrawer()
The Problem
This issue can occur when you do not use the correct BuildContext when calling Scaffold.of(context).openDrawer() (or openEndDrawer()).
Easiest Solution
Simply wrap whatever calls openDrawer() (or openEndDrawer()) with a Builder widget. This will give it a working context.
Minimal Working Example
// your build method
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Builder(builder: (context) { // this uses the new context to open the drawer properly provided by the Builder
return FloatingActionButton(onPressed: (() => Scaffold.of(context).openDrawer()));
}),
drawer: const Drawer(
child: Text("MY DRAWER"),
),
);
}
Similar problem here. Clicked on button and nothing happened. The problem is I was using the context of the widget that instantiated Scaffold. Not the context of a child of Scaffold.
Here is how I solved it:
// body: Column(
// children: <Widget>[
// Row(
// children: <Widget>[
// IconButton(
// icon: Icon(Icons.filter_list),
// onPressed: () => Scaffold.of(context).openEndDrawer(), (wrong context)
// ),
// ],
// ),
// ],
// )
To:
body: Builder(
builder: (context) => Column(
children: <Widget>[
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () => Scaffold.of(context).openEndDrawer(),
),
],
),
],
)),
),
Assign Drawer to drawer property in scaffold. Wrap your specific Widget/Button(where you want to open drawer on its click method) with Builder. Use below method on click property:
enter image description here
Scaffold.of(context).openDrawer();
If you have the appbar widget with an action button to launch the drawer and the drawer is never pushed please remember that you need to define after appbar: ... the endDrawer: YOURAppDrawerWIDGET(), or else using the Scaffold.of(context).openEndDrawer() will not work.
Scaffold(
appBar: AppBar(title: Text(_title)),
endDrawer: AppDrawer(), // <-- this is required or else it will not know what is opening
body: SingleChildScrollView(
///...