Getting error when I use Media Query in flutter web? - flutter

Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size.width;
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: ( !kisweb || screenSize <= 600) ? MyHomePageMobile() : MyHomePage(),
),
);
}
I am getting this error and I have no idea how to solve it

You can't declare the MediaQuery above the Material app and it needs context. So the proper declaration should be like this.
class Main extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Test(),
);
}
}
class Test extends StatelessWidget {
const Test({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size.width;
return Container(
child: Scaffold(
body: ( !kisweb || screenSize <= 600) ? MyHomePageMobile() : MyHomePage(),
),
);
}
}

Related

Flutter web set a white screen at height less than 500px

I would like to set a white screen when someone resizes the height of their tab to a small size
It works for the initial route however, I would like to do this for all my screens
Here is my code
class _ExcelitState extends State<Excelit> {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
key: navigatorKey,
debugShowCheckedModeBanner: false,
onUnknownRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) =>
const Scaffold(body: Center(child: Text('Page Not Found!!!'))),
);
},
// navigatorObservers: [observer],
routes: {
'/': (context) => (kIsWeb && setHeight(context, 0.01) <= 5)
? const EmptyScreen()
: const LoginScreen(),
},
);
}
}
class EmptyScreen extends StatelessWidget {
const EmptyScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: kBackgroundColor,);
}
}
I did the following:
IndexedStack would save the state and once the screen height on the web is below ~500px I change to the empty screen
yet I had to change all my Scaffolds to CustomScaffold
import 'package:excelit/constants/constants.dart';
import 'package:excelit/main.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class CustomScaffold extends StatelessWidget {
const CustomScaffold({Key? key, required this.widget}) : super(key: key);
final Widget widget;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kBackgroundColor,
resizeToAvoidBottomInset: true,
body: IndexedStack(
index: (kIsWeb && setHeight(context, 0.01) <= 5) ? 1 : 0,
children: [
widget,
const EmptyScreen(), //if height is reduced below ~500px show white screen
],
),
);
}
}
class EmptyScreen extends StatelessWidget {
const EmptyScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: kBackgroundColor,);
}
}

Why am i getting No MediaQuery widget ancestor found .error

I have checked some threads here on StackOverlow but they dont fix my problem.The suggestions are
Create a new Stateless/Stateful widget and pass it to the home parameter OR
Use the Builder widget and pass it to the home parameter.
which I already did.
This is my main.dart file
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
ScreenUtil.init(context,designSize: Size(360,640));
return MaterialApp(
title: 'Flutter Demo',
home: HomeScreen()
);
}
}
And this is home.dart file
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Row(
children: [
buildLeftColumn(),
SizedBox(
width: 20.w,
),
// buildRightColumn(),
],
)),
);
}
buildLeftColumn() {
return Container();
}
So. what am i doing wrong.Could you please help
If you like to use ScreenUtil.init(...) you can solve this issue calling it on HomeScreen widget(context).
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
ScreenUtil.init(context, designSize: Size(360, 640));
To use it before MaterialApp you can use ScreenUtilInit widget.
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(360, 640),
builder: (context, child) => MaterialApp(
title: 'Flutter Demo',
home: HomeScreen(),
),
);
}

Flutter's MediaQuery rectangle seems incorrect

A Rect with a top-left at (0, 0) and sized MediaQuery.of(context).size should match exactly the rectangle left after the AppBar rectangle is present.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(scaffoldBackgroundColor: const Color(0xFF80EFEF)),
home: Scaffold(
appBar: AppBar(
title: Text('MyApp'),
),
body: MyWidget()));
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
var deviceData = MediaQuery.of(context);
return CustomPaint(painter: MyPainter(appSize: deviceData.size));
}
}
class MyPainter extends CustomPainter {
Size appSize;
MyPainter({this.appSize});
#override
void paint(Canvas canvas, Size size) {
var paint = Paint()..color = Colors.indigo;
const double margin1 = 70;
canvas.drawRect(
Rect.fromLTWH(margin1, margin1, appSize.width - 2 * margin1,
appSize.height - 2 * margin1),
paint);
}
#override
bool shouldRepaint(MyPainter oldDelegate) => false;
}
As you see here:
it does not. It protrudes (when targeting chrome) from the bottom. We're only able to see that when we use a margin to reduce the rectangle's size.
Why does the rectangle not match the expected area? Is this a bug?
You can use layoutbuilder to know the exact remaining space left.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('LayoutBuilder Example')),
body: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Text('Width: ${constraints.maxWidth} Height: ${constraints.maxHeight}');
},
),
);
}
When we write a Widget class such as
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
var deviceData = MediaQuery.of(context);
return CustomPaint(painter: MyPainter(appSize: deviceData.size));
}
}
and make a MediaQuery.of(), the context that we are querying is not that of MyWidget. It is the context of the parent of MyWidget in the widget objects tree.
In this case the parent is the Scaffold. Hence the context we get does include the AppBar!
(To make it clearer, it would perhaps be more apt to write parentContext, rather than context.)
The solution is to add an intermediate "dummy" parent widget that has the correct dimensions.
This does not need to be a full-fledged new class. Using either Builder or LayoutBuilder is enough.
Using Builder doesn't cut it (why?)
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: new ThemeData(scaffoldBackgroundColor: const Color(0xFF80EFEF)),
home: Scaffold(
appBar: AppBar(
title: Text('MyApp'),
),
body: Builder(
builder:
(BuildContext context) {
return MyWidget();
},
)));
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
var deviceData = MediaQuery.of(context);
return CustomPaint(painter: MyPainter(appSize: deviceData.size));
}
}
Hence we need to use, as in Ayad's answer, LayoutBuilder.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: new ThemeData(scaffoldBackgroundColor: const Color(0xFF80EFEF)),
home: Scaffold(
appBar: AppBar(
title: Text('MyApp'),
),
body: LayoutBuilder(
builder:
(BuildContext context, constraints) {
return MyWidget(size: Size(constraints.maxWidth, constraints.maxHeight));
},
)));
}
}
class MyWidget extends StatelessWidget {
Size size;
MyWidget({this.size}) {}
#override
Widget build(BuildContext context) {
return CustomPaint(painter: MyPainter(appSize: size));
}
}
We then see that we have the correct Size.

Flutter Custom TextTheme With Adaptive TextSize

I created custom ThemeDatas (light & dark), when I launch my app with them I get a _mulFromInteger() issue. This is because the FontSizes in TextTheme inside my ThemeData have values that change according to the screen size, to make these adaptive FontSizes I use a class that contains my size configurations. This class calls MediaQuery.of(context) that will modify my screen configurations in function to it's value. The problem is that I call my ThemeData (with the TextTheme) before I call my SizeConfigurations.init(context). If I try putting my init before creating my MaterialApp and setting the theme it tells me I used a context without a MediaQuery. Any idea how to solve this? Thanks :)
Code:
#override
Widget build(BuildContext context) {
// When I call SizeConfig().init(context); here it tells me the context doesn't have a MediaQuery
return MaterialApp(
theme: AppTheme.getLightTheme(),
darkTheme: AppTheme.getDarkTheme(),
themeMode: ThemeMode.system,
title: 'App Title',
onGenerateRoute: NavigationRouter.generateRoute,
home: FutureBuilder(
future: jwtOrEmpty,
builder: (context, snapshot) {
SizeConfig().init(context);
…
}
),
);
}
You can copy paste run full code below
You can use MediaQueryData.fromWindow(ui.window)
code snippet
void init() {
_mediaQueryData = MediaQueryData.fromWindow(ui.window);
_screenWidth = _mediaQueryData.size.width;
_screenHeight = _mediaQueryData.size.height;
full code
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
class SizeConfig {
static MediaQueryData _mediaQueryData;
static double _screenWidth;
static double _screenHeight;
double get screenWidth => _screenWidth;
double get screenHeight => _screenHeight;
void init() {
_mediaQueryData = MediaQueryData.fromWindow(ui.window);
_screenWidth = _mediaQueryData.size.width;
_screenHeight = _mediaQueryData.size.height;
print(_screenWidth);
print(_screenHeight);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
SizeConfig().init();
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
print(MediaQuery.of(context).size.width);
print(MediaQuery.of(context).size.height);
print(SizeConfig().screenWidth);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Flutter, bottomSheet seems to be in loop

I have a screen that at bottom should load a banner. But when I run, the log goes crazy printing Banner mount and the banner never shows up.
But if I remove it (BannerComponent) from bottomSheet the banner works without the crazy print in loop.
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new StoreProvider<BookmarkState>(
store: store,
child: new MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
},
),
);
}
}
class HomeScreen extends StatelessWidget {
static const int PAGE_SIZE = 5;
#override
Widget build(BuildContext context) {
// return BannerComponent() // this whill work
return Scaffold(
appBar: AppBarComponent(),
drawer: DrawerComponent(),
// body: this.mountBody(context),
bottomSheet: BannerComponent(),
);
}
}
class BannerComponent extends StatelessWidget {
BannerComponent();
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: Row(
children: [
this.mountDFPBanner(context),
],
));
}
mountDFPBanner(context) {
print('Banner mount');
return DFPBanner(...);
}
}
So, what could I be doing wrong here?
https://github.com/ko2ic/flutter_google_ad_manager/issues/33
#Pablo, I am not sure how you're calling your HomeScreen but that could be the issue here. I did a quick test calling it within MaterialApp and seems to be working fine,
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
static const int PAGE_SIZE = 5;
#override
Widget build(BuildContext context) {
// return BannerComponent() // this whill work
return Scaffold(
appBar: AppBar(
title: Text('Test')),
//drawer: DrawerComponent(),
// body: this.mountBody(context),
bottomSheet: BannerComponent(),
);
}
}
class BannerComponent extends StatelessWidget {
BannerComponent();
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: Row(
children: [
this.mountDFPBanner(context),
],
)
);
}
mountDFPBanner(context) {
print('Banner mount');
return Container(padding: EdgeInsets.only(left: 5.0),height: 40.0, alignment: Alignment.center, child: Text('Banner Test', style: TextStyle(color: Colors.white, fontSize: 18.0),));
}
}
Screenshot:
Hope this helps.