if condition to run Widget at Container flutter - flutter

if condition when post.text == 1
i setup Widget named exteranews
Widget exteranews(BuildContext context) {
double siz11 = 15.0 * MediaQuery.of(context).size.width / 414.0;
}
how to use if with that Container
Container(
if (checkothers) child: exteranews(context),
),
i set String checkothers = post.text;
i read i have to setup Widget to use run exteranews() but how to use if condition with it

You may use ? syntax
please make sure to put Container() so it will display nothing
its easier to image Container() equals to <div></div> in html
Widget extraNews(BuildContext context) {
double siz11 = 15.0 * MediaQuery.of(context).size.width / 414.0;
return Container();
}
class BaseScreen extends StatelessWidget {
///
#override
Widget build(BuildContext context) {
return Container(
child: checkothers == true ? extraNews(context) : Container(),
);
}
}

Related

Flutter Web Responsiveness is not efficient

My screen have total 5 device partition size:- 1.Desktop 2.Small Desktop 3.Tablet 4.Small Tablet 5.Mobile,
for that purpose i tried to use layout builder but while i'm resizing the size of display it's take too much time to render the design because it's trying to rebuild the design at every breakpoints.which is not expected in web design,is there any alteranative way to acheive smooth responsiveness in flutter web.
class CommunityListScreen extends StatefulWidget {
static const String id = 'community_list_screen';
const CommunityListScreen({Key? key}) : super(key: key);
#override
State<CommunityListScreen> createState() => _CommunityListScreenState();
}
class _CommunityListScreenState extends State<CommunityListScreen> {
late double _deviceWidth;
late double _deviceHeight;
#override
Widget build(BuildContext context) {
_deviceWidth = MediaQuery.of(context).size.width - 150;
_deviceHeight = MediaQuery.of(context).size.height;
print(_deviceWidth);
return Scaffold(
backgroundColor: ColorAssets.themeColorLightGrey,
body: Container(
///responsive builder
margin: const EdgeInsets.only(top: 15.0),
child: LayoutBuilder(
builder: (context, constraint) {
///desktop size
if (constraint.maxWidth >= 1200) {
return desktop();
} else if (constraint.maxWidth >= 1000) {
return smallDesktop();
} else if (constraint.maxWidth >= 800) {
return tablet();
} else if (constraint.maxWidth >= 600) {
return smallTablet();
} else if (constraint.maxWidth >= 300) {
return mobile();
}
return Container(color: ColorAssets.themeColorLightPurple);
},
),
),
);
}
}
i found the exact issue,the time was taken by dottenline package which i used in my table format design, i removed this package and now the page rendering smoothly as per screen size.

Flutter web - How to listen on open Drawer state and close it

Im working on flutter responsive web UI. And I want to close the opened drawer on a specific screen width for mobile and desktop screen width, so if I stretch my browser, the drawer should close.
For example I opened the drawer (screen width less than 500)
And when the screen width is greater than 500, I want the opened drawer to automatically close.
Note: When the Drawer is opened. I have a code already that checked the screen width that show a button menu drawer or not. But basically, when the user open the drawer then suddenly stretch the browser the drawer should closed.
Code below. Thanks for the help
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size.width;
return Scaffold(
drawer: Drawer(),
body: CustomNavBar(screenSize: size),
);
}
}
class CustomNavBar extends StatefulWidget {
final double screenSize;
const CustomNavBar({Key key, this.screenSize}) : super(key: key);
#override
_CustomNavBarState createState() => _CustomNavBarState();
}
class _CustomNavBarState extends State<CustomNavBar> {
#override
Widget build(BuildContext context) {
if (Scaffold.of(context).isDrawerOpen && widget.screenSize > 500) {
print("Drawer is Opened");
Scaffold.of(context).openEndDrawer(); //animation error
setState(() {});
}
return widget.screenSize > 500
? Container(color: Colors.red) //desktop screen
: Center(
//mobile screen
child: IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
),
);
}
}
You shouldn't have to close the drawer manually. Why not just get rid of the drawer when the screen width is less than 500?
class SampleDrawer extends StatelessWidget {
final GlobalKey<ScaffoldState> k = GlobalKey();
#override
Widget build(BuildContext context) {
// new
final size = MediaQuery.of(context).size.width;
if (k.currentState.isDrawerOpen && size < 500) {
Navigator.pop(context); // close drawer
}
return Scaffold(
key: k,
drawer: size > 500 ? Drawer() : null,
body: CustomNavBar(),
);
}
}
class CustomNavBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size.width;
return size > 500
? Container(color: Colors.red) //desktop screen
: Center( //mobile screen
child: IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
),
);
}
}
The Scaffold will be rebuilt whenever the width of the device changes, and the drawer will automatically be omitted if the width is less than 500.
Here is the Solution.
You're Code is enough. Just a few changes to your code
Wrap this Scaffold.of(context).openEndDrawer(); in
WidgetsBinding.instance.addPostFrameCallback((_) {
Scaffold.of(context).openEndDrawer(); //No Error
///The Error was coming, As you're trying to build a widget when it is
///rebuilding widget Tree due to the change in the width of the browser.
///Wrapping it inside ensures that the code will run after the build.
});
Don't Use setState(() {});
Use 520 instead of 500
Reason
The error was coming, As you're trying to build a widget when it is
rebuilding Widget Tree due to the change in the width of the browser.
Wrapping this Scaffold.of(context).openEndDrawer(); inside WidgetsBinding.instance.addPostFrameCallback((_) {}); ensures that the code will run after the widget get's build.
Here's Updated Code
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size.width;
print(size);
return Scaffold(
drawer: Drawer(),
body: CustomNavBar(
screenSize: size,
),
);
}
}
class CustomNavBar extends StatefulWidget {
final double screenSize;
const CustomNavBar({
Key key,
this.screenSize,
}) : super(key: key);
#override
_CustomNavBarState createState() => _CustomNavBarState();
}
class _CustomNavBarState extends State<CustomNavBar> {
#override
Widget build(BuildContext context) {
if (Scaffold.of(context).isDrawerOpen && widget.screenSize > 520) {
print("Drawer is Opened");
WidgetsBinding.instance.addPostFrameCallback((_) {
Scaffold.of(context).openEndDrawer(); //No Error
///The error was coming, As you're trying to build a widget when it is
///rebuilding widget Tree due to the change in the width of the browser.
///Wrapping it inside ensure that the code will run after the build.
});
// Don't call setState((){}); Not Required;
// as every time you change the width it rebuilds all the widget again
// setState(() {});
}
return widget.screenSize > 520
? Container(color: Colors.red) //desktop screen
: Center(
//mobile screen
child: IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
),
);
}
}
The error was
The following assertion was thrown while notifying status listeners for
AnimationController:
setState() or markNeedsBuild() called during build.
This Scaffold widget cannot be marked as needing to build because the framework is
already in the
process of building widgets. A widget can be marked as needing to be built during
the build phase
only if one of its ancestors is currently building. This exception is allowed
because the framework
builds parent widgets before children, which means a dirty descendant will always be
built.
Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
Scaffold
The widget which was currently being built when the offending call was made was:
CustomNavBar
Tip
Use the Layout Builder for Responsive UI.
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 800) {
return XScreen();
} else if (constraints.maxWidth < 1200 && constraints.maxWidth > 800) {
return Yscreen()?? ZScreen();
} else {
return XScreen()?? ZScreeen();
}
},
);
}
With Flutter 2.0 here is proper way to detect drawer open/close:
Scaffold(
onDrawerChanged: (isOpened) {
//listener left drawer
},
onEndDrawerChanged: (isOpened) {
//listener right drawer
},
)

Is it possible to extend a StatefulWidget that provides an extra parameter on its build method?

I would like to create a BaseScreen Widget like this to reuse in my app:
class BaseScreen extends StatelessWidget {
final Widget child;
BaseScreen({this.child});
#override
Widget build(BuildContext context) {
var safePadding = MediaQuery.of(context).padding.top +
MediaQuery.of(context).padding.bottom;
return Scaffold(
body: LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: SafeArea(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraint.maxHeight - safePadding),
child: IntrinsicHeight(
child: child,
),
),
),
);
},
),
);
}
}
But the problem I see is that I would also like to reuse the constraint property that LayoutBuilder provides in the child of this class.
Currently, I need to create yet a new LayoutBuilder in the child, and that just sounds like more processing for the engine, and more boilerplate code.
If I could extend somehow this Widget so that in the child I could then have this:
#override
Widget build(BuildContext context, BoxConstraints constraints) {
}
That would be great. I know Flutter encourages composition over inheritance as well, so if I can solve it in another way, I'd also appreciate that.
Thank you!
TL;DR : No, use InheritedWidget to pass variables/data to child widgets, read more about it in here and here
Why not?
In Dart language it is only possible to add optional/named non-conflicting parameters to overridden methods.
For example:
class SuperClass {
void someMethod(String parameter1) {}
}
class SubClass1 extends SuperClass {
// adding optional parameter
#override
void someMethod(String paremeter1, [String paremter2]) {}
}
class SubClass2 extends SuperClass {
// adding optional named parameter
#override
void someMethod(String paremeter1, {String paremter2}) {}
}
Note: Dart does not support method overloading which means is a compile error to have two methods with same name but different parameters.
Now if you add BoxConstraints constraints in your build() method like this
#override
Widget build(BuildContext context, [BoxConstraints constraint]){
/// Your code
}
It will compile but who is going to give you that [constraint] parameter?
As developers we never call the build() method ourselves, the flutter framework calls that method for us.
Reason for that: Calling the build() method ourselves would be difficult because it requires context, and providing correct context value is something that only flutter framework does correctly. Most new developers pass around the context variable but it's not guaranteed if that will always work, because the place of the widget in the widget tree determines what is the correct context value for that widget. And during writing code, there is no easy way to figure out what is the exact place of the widget in the widget tree. Even if somehow we could figure out the place, what is the value of context for that place? Because flutter provides that value, how that value is created is for another post.
Solutions
There are two easy and very common solutions in flutter for passing data/variables to child widgets,
Using WidgetBuilder variants
Using InheritedWidget (Recommended)
Solution 1. Using WidgetBuilder variants
WidgetBuilder is a function that takes BuildContext and returns a Widget, sounds familiar?, it's the type definition of the build() method. But we already have build() method available, what's the point of WidgetBuilder?. The most common use case is for scoping the BuildContext.
For example:
If you click on "Show snackbar" it will not work and instead throw and error saying "Scaffold.of() called with a context that does not contain a Scaffold."
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FlatButton(
onPressed: () {
/// This will not work
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text('Hello')));
},
child: Text('Show snackbar'),
),
)
);
}
You might think, there is clearly a Scaffold widget present, but it says there is no scaffold? This is because the following line is using context provided by a widget above the Scaffold widget (the build() method).
Scaffold.of(context).showSnackBar(SnackBar(content: Text('Hello')));
If you wrap the FlatButton with the Builder widget, it will work try it.
Like many flutter widgets you could create a WidgetBuilder variant that provides additional parameters while building the widget like FutureBuilder's AsyncWidgetBuilder or like LayoutBuilder's LayoutWidgetBuilder
For example:
class BaseScreen extends StatelessWidget {
/// Instead of [child], a builder is used here
final LayoutWidgetBuilder builder;
const BaseScreen({this.builder});
#override
Widget build(BuildContext context) {
var safePadding = MediaQuery.of(context).padding.top +
MediaQuery.of(context).padding.bottom;
return Scaffold(
body: LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: SafeArea(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraint.maxHeight - safePadding,
),
/// Here we forward the [constraint] to [builder],
/// so that it can forward it to child widget
child: builder(context, constraint),
),
),
);
},
),
);
}
}
And this is how you use it (Just like LayoutBuilder, but the child gets the parent widget's LayoutBuilder's constraint and only one LayoutBuilder is required
#override
Widget build(BuildContext context) {
return BaseScreen(
builder: (context, constraint) {
// TODO: use the constraints as you wish
return Container(
color: Colors.blue,
height: constraint.minHeight,
);
},
);
}
Solution 2. Using InheritedWidget (Recommended)
Sample InheritedWidget
/// [InheritedWidget]s are very efficient, in fact they are used throughout
/// flutter's source code. Even the `MediaQuery.of(context)` and `Theme.of(context)`
/// is actually an [InheritedWidget]
class InheritedConstraint extends InheritedWidget {
const InheritedConstraint({
Key key,
#required this.constraint,
#required Widget child,
}) : assert(constraint != null),
assert(child != null),
super(key: key, child: child);
final BoxConstraints constraint;
static InheritedConstraint of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<InheritedConstraint>();
}
#override
bool updateShouldNotify(covariant InheritedConstraint old) =>
constraint != old.constraint;
}
extension $InheritedConstraint on BuildContext {
/// Get the constraints provided by parent widget
BoxConstraints get constraints => InheritedConstraint.of(this).constraint;
}
Your child widget can access the BoxConstraints provided by this inherited widget like this
class ChildUsingInheritedWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
/// Get the constrains provided by parent widget
final constraint = context.constraints;
// TODO: use the constraints as you wish
return Container(
color: Colors.green,
height: constraint.minHeight,
);
}
}
And this is how you use connect these two widgets
In your BaseScreen wrap the child with InheritedConstraint
class BaseScreen extends StatelessWidget {
final Widget child;
const BaseScreen({this.child});
#override
Widget build(BuildContext context) {
var safePadding = MediaQuery.of(context).padding.top +
MediaQuery.of(context).padding.bottom;
return Scaffold(
body: LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: SafeArea(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraint.maxHeight - safePadding,
),
child:
InheritedConstraint(constraint: constraint, child: child),
),
),
);
},
),
);
}
}
And you can use the BaseScreen anywhere you like
For example:
#override
Widget build(BuildContext context) {
return BaseScreen(child: ChildUsingInheritedWidget());
}
See this working DartPad example: https://dartpad.dev/9e35ba5c2dd938a267f0a1a0daf814a7
Note: I noticed this line in your example code:
var safePadding = MediaQuery.of(context).padding.top +
MediaQuery.of(context).padding.bottom;
If you are trying to get the padding provided by SafeArea() widget, then that line will not give you correct padding, because it's using wrong context it should use a context that is below SafeArea() to do that, use the Builder widget.
Example:
class BaseScreen extends StatelessWidget {
final Widget child;
const BaseScreen({this.child});
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: SafeArea(
child: Builder(
builder: (context) {
var safePadding = MediaQuery.of(context).padding.top +
MediaQuery.of(context).padding.bottom;
return ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraint.maxHeight - safePadding,
),
child: child,
);
},
),
),
);
},
),
);
}
}
Of course you can. It will look something like this
abstract class BoxConstraintsWidget extends StatelessWidget {
Widget build(BuildContext context, BoxConstraints constraints);
#override
Widget build(BuildContext context) {
return build(context, BoxConstraints());
}
}
Then override it like
class BoxConstraintsWidgetChild extends BoxConstraintsWidget{
#override
Widget build(BuildContext context, BoxConstraints constraints) {
return someStuff;
}
}
There is one tiny problem though - Widget build(BuildContext context) is an inner framework method and you cannot force it to be called with more that one parameter(of course if you do not want to rewrite the complete flutter by yourself). The thing is you may use the approach above but add this BoxConstraints constraints as some getter in your base class with the default implementation and override it in its child if you want to. It will look like this:
abstract class BoxConstraintsWidget extends StatelessWidget {
BoxConstraints get constraints => BoxConstraints();
Widget build(BuildContext context, BoxConstraints constraints);
#override
Widget build(BuildContext context) {
return build(context, constraints);
}
}
And use it as it is or override it as
class BoxConstraintsWidgetChild extends BoxConstraintsWidget{
#override
BoxConstraints get constraints => MyBoxConstraints();
#override
Widget build(BuildContext context, BoxConstraints constraints) {
//here you will have you copy of constraints that = MyBoxConstraints()
//without overriding method you would have had a parent constraints that = BoxConstraints()
return someStuff;
}
}
This is only one approach and it maybe a little redundant one but you may experiment. You may use it without an inheritance.
Also you may experiment with custom Builders for your widget that will work like ListView.builder(), LayoutBuilder() or FutureBuilder(). I would recommend you to investigate how do they work.
Also you can create a custom constructor for your child widget that receives BoxConstraints as a parameter and stores it is the widget to be user either in a State or StatelessWidget builders.
There are many more ways to do it most of which will be a different implementations of simple composition so yeah... experiment))
Hope it helps.

How to make one widget disappear when another widget is clicked?

My page has two stateful widgets (say A and B). When A is clicked, I want to B to disappear and then A to occupy the full width of the screen. I cannot figure out how to make B disappear.
A is expanded as expected but the presence of B is causing an overflow. I tried using ValueListenableBuilder to pass a variable which will then trigger the visibility of B to become false but couldn't implement it.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter layout demo',
home: Scaffold(
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[HeadCardApp("Society", 'assets/houses.png', 1), //Widget A
HeadCardApp("Community",'assets/discuss.png', 2)], //Widget B
),
),
);}
}
}
class HeadCardApp extends StatefulWidget {
final String heading;
final String imgLink;
final int stateNo;
HeadCardApp(this.heading, this.imgLink, this.stateNo);
#override
HeadCard createState() => HeadCard(heading, imgLink, stateNo);
}
class HeadCard extends State<HeadCardApp> {
String heading;
String imgLink;
double _width = 380;
double _height = 180;
int stateNo;
HeadCard(this.heading, this.imgLink, this.stateNo);
#override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: (){
if(stateNo == 1){
//Space to make changes
}
else
{
}
setState(() {
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
});
},
child: AnimatedContainer(
width: _width,
height: _height,
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
),
));
}
}```
you can put the Column part of the MaterialApp inside a StatfulWidget an like that you can change the visibility by calling setState in the new StatfulWiget to change view visibility.

How to pass the widget as a parameter to the function

I want to pass some widgets as a parameter to function, does flutter support that? Below is my code. Should I pass a widget as a parameter to function?
This is the widget that I want to pass as a parameter:
class FirstWidget extends StatelessWidget {
#override
Widget build(BuildContext context){
return Container(
child: Text('i am the first'),
);
}
}
class SecondWidget extends StatelessWidget {
#override
Widget build(BuildContext context){
return Container(
child: Text('i am the second'),
);
}
}
createWidget is the important:
class Main extends StatelessWidget {
// maybe return a widget i wanna, maybe return a default widget.
Widget _createWidget(widget){
// do something to judge
if(dosomething){
return Container(
child: Text('nothing'),
);
}
// i wanna `widget()` at this postion. not when `_createWidget`
return widget();
}
#override
Widget build(BuildContext context){
return Column(
children: <Widget>[
_createWidget(FirstWidget),
_createWidget(SecondWidget),
],
);
}
}
You can pass an instance of the Widget to your function and then return it:
#override
Widget build(BuildContext context){
return Column(
children: <Widget>[
_createWidget(FirstWidget()),
_createWidget(SecondWidget()),
],
);
}
Widget _createWidget(Widget widget) {
// ... other stuff...
return widget;
}
Or if you want to defer constructing FirstWidget() and SecondWidget() until after you've called _createWidget() (for example, if you want _createWidget to return the constructed widget conditionally), you could use an anonymous function to create a thunk:
#override
Widget build(BuildContext context){
return Column(
children: <Widget>[
_createWidget(() => FirstWidget()),
_createWidget(() => SecondWidget()),
],
);
}
Widget _createWidget(Widget Function() widgetBuilder) {
// ... other stuff...
return widgetBuilder();
}
You can pass anything to a function.
Change your function definition as follow:
Widget _createWidget(Widget child){
// do something to judge
if(dosomething){
return Container(
child: Text('nothing'),
);
}
// Notice that you just return the variable and not call it as a function.
// return child(); <-- this one will result in an error
return child; // <-- this is the right way
}