I am creating reusable stateless widget for troubleshooting and maintenance. MyApp1 is a statelesswidget and am calling this widget MyApp1(title: 'title',) from a statefull widget.In order to segregate many lines of code and make troubleshooting simpler, another widgets firstone and Secondone are created. Here am passing a title data. I made two widgets firstone (widget function) and SecondOne (Statelesswidget). Although I am showing a text in both, the outcome differs.
class MyApp1 extends StatelessWidget {
final String title;
const MyApp1({super.key,required this.title});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Text(title,style: Theme.of(context).textTheme.titleLarge),
firstone(context),
SecondOne(title: 'title'),
],
),
),
);
}
Widget firstone(context){
return Text(title,style: Theme.of(context).textTheme.titleLarge);
}
}
class SecondOne extends StatelessWidget {
final String title;
const SecondOne({Key? key,required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Text(title,style: Theme.of(context).textTheme.titleLarge);
}
}
Although the text styles are identical in both, my output is different. I don't have to supply the title data twice when using firstone (the widget function). Which is preferable: Stateless widgets or widget functions? If I use a stateless widget, I transmit data from a stateful widget to Myapp1 stateless widget and then to a second widget. Is this correct
My Output:
Classes should be preferred over functions that return widgets.
It's different because you're manually passing a BuildContext which is provided above the scope of where the default ThemeData can be accessed from (is provided by MaterialApp).
class MyApp1 extends StatelessWidget {
final String title;
const MyApp1({super.key,required this.title});
#override
Widget build(BuildContext context) { // <- this BuildContext is being used
return MaterialApp( // <- this widget provides the `ThemeData`, which isn't accessible from the above context
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Text(title,style: Theme.of(context).textTheme.titleLarge), // <- refers to the `context` provided by build above
firstone(context), // <- refers to the `context` provided by build above
SecondOne(title: 'title'),
],
),
),
);
}
Widget firstone(context){
return Text(title,style: Theme.of(context).textTheme.titleLarge);
}
class SecondOne extends StatelessWidget {
final String title;
const SecondOne({Key? key,required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
// This uses the correct context, inherited from `MaterialApp` properly.
return Text(title,style: Theme.of(context).textTheme.titleLarge);
}
}
Please do not return MaterialApp .
Direct return column in myapp1 class.
It will solve your issue
Related
If I run the following application and observe the hashCodes for BuildSizedBoxWidget which I create two instances of, I notice that they are the same even when I hot reload the app. Does this mean that they are the same widget but referenced multiple times? ... But in case of BuildContainerWidget the hashCodes change every time I hot reload the app. Why does this happen?
'''
import 'package:flutter/material.dart';
void main() {
runApp(const MyApps());
}
class MyApps extends StatelessWidget {
const MyApps({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Test',
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
final List<Widget> widgets = const [
BuildSizedBoxWidget(),
BuildSizedBoxWidget(),
BuildContainerWidget(),
BuildContainerWidget()
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('What is happening'),
),
body: Column(
children: widgets,
),
);
}
}
class BuildSizedBoxWidget extends StatelessWidget {
const BuildSizedBoxWidget({super.key});
#override
Widget build(BuildContext context) {
const Widget widget = SizedBox(height: 50, child: Text('test'));
print(widget.hashCode);
return widget;
}
}
class BuildContainerWidget extends StatelessWidget {
const BuildContainerWidget({super.key});
#override
Widget build(BuildContext context) {
Widget widget = Container(height: 50, color: Colors.red);
print(widget.hashCode);
return widget;
}
}
'''
The variables defined in the body of the build method will be re-initialized during SetState.
Variables specified by the const keyword are not initialized.
There are only three parameters required by SizeBox Widget, and all of them can be initialized.
But Container Widget contains many parameters that cannot be initialized. So Container cannot be specified with the const keyword
If you put them outside the body of the build method, the HasCode will not change
class BuildContainerWidget extends StatelessWidget {
BuildContainerWidget({super.key});
Widget widget = Container(key: Key('value'), height: 50, child: Text('test'));
#override
Widget build(BuildContext context) {
print(widget.hashCode);
return widget;
}
}
Let's say I have this HomePage widget:
class HomePage extends StatelessWidget {
const HomePage({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(),
);
}
}
I am able to use a const constructor at the root (MaterialApp widget) because all children do have const constructors too.
If I add the AppBar widget, I will have to remove the const constructor from the root, because AppBar does not have a const constructor.
class HomePage extends StatelessWidget {
const HomePage({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp( // no const anymore
home: Scaffold(
appBar: AppBar(...),
),
);
}
}
But why am I able to use the HomePage widget with a const constructor ? See code below:
class App extends StatelessWidget {
const App({super.key});
#override
Widget build(BuildContext context) {
return const HomePage(); // using a const constructor
}
}
I thought it would be impossible because of the AppBar child widget.
Because the HomePage class is immutable. The build function implementation doesn't affect it.
The const keyword can be used when the object is immutable. A Compiler allocates the same portion of memory for all objects.
For more info, reference the Using constructors: Dart doc
I need to calculate the height of a child widget before its parent renders.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Material App',
home: Scaffold(
appBar: CustomAppbar(
widget: Text(
'This is a tex',
),
),
),
);
}
}
The above code just call a Widget CustomAppbar, which receives as parameter a TEXT widget
class CustomAppbar extends StatelessWidget implements PreferredSizeWidget {
final Widget? widget;
const CustomAppbar({
Key? key,
this.widget,
}) : super(key: key);
#override
Size get preferredSize => const Size.fromHeight(130.0);
#override
Widget build(BuildContext context) {
return ClipPath(
clipper: HeaderCustomClipper(),
child: ColoredBox(
color: Color.fromRGBO(255, 191, 14, 1),
child: Column(
children: [
_AppBar(),
if (widget != null) widget as Widget,
],
),
),
);
}
}
The above code just is a customAppbar, I want the height of the child widget (widget) to be captured before the CustomAppbar renders.
If I pass a text, it should be seen like that:
If I don't pass anything, it should be seen like that:
to achieve that you can use GlobalKey -> BuildContext -> RenderBox -> widget-> global position & rendered size.
please check this below link
https://stackoverflow.com/a/49650741/17180860
I'm trying to do my school assignment, and have run into difficulty with passing data into Stateless Widgets. I have the following classes:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Page1(),
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Page2(messageData: messageData)));
},
child: Text('Request Chat'),
)),
);
}
}
class Page2 extends StatelessWidget {
//Navigation
static Route route(MessageData data) => MaterialPageRoute(
builder: (context) => Page2(
messageData: data,
),
);
const Page2({Key? key, required this.messageData}) : super(key: key);
final MessageData messageData;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: Theme.of(context).iconTheme,
centerTitle: false,
),
),
},
#immutable
class MessageData {
const MessageData(
{required this.senderName,
required this.message,
required this.messageDate,
required this.dateMessage,
required this.profilePicture});
final String senderName;
final String message;
final DateTime messageDate;
final String dateMessage;
final String profilePicture;
}
There is my messageData above that I need to pass.
Basically, I want to be able to Navigate to Page2 but I keep getting an error at Navigator.push() .
Error details: Type' can't be assigned to the parameter type 'MessageData'.
And when there are no arguments on Page2() the error message: The named parameter 'messageData' is required, but there's no corresponding argument.
You have to pass data using Constructor. I hope you will get an idea from this link.
You can pass arguments to widgets just like you pass to Flutter's widgets:
///Creating Page2 instances
Page2(text: 'text');
Page2.otherConstructor('text');
///This is how you pass values to widgets
class Page2 extends StatelessWidget {
//Pass `this.field` to the constructor so that you are asking for the field you created.
const Page2({Key? key, required this.text}) : super(key: key);
const Page2.otherConstructor(this.text);
final String text;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text(text),
);
}
}
And in case it's a StatefulWidget in the State you can access the values with widget.field.
I want to populate a column inside my scaffold body with my MyContainer widget, but I was not able to access properties of the parent widget in child widget. MyContainer class is working fine but using MyColumn widget does not.
Here is my code:
import 'package:flutter/material.dart';
void main(List<String> args) {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Title(
color: const Color(0xFFFFFFFF),
child: const Text("Hello World App")),
),
body: MyColumn(),
),
);
}
}
class MyContainer extends Container {
late int numbr;
MyContainer(numbr) {
this.numbr = numbr;
}
#override
// TODO: implement color
Color? get color => Colors.blue;
#override
// TODO: implement child
Widget? get child => Center(
child: Text("Container $numbr",
style: TextStyle(
fontSize: 34, fontFamily: "Cursive", color: Colors.white)),
);
}
class MyColumn extends Column {
#override
// TODO: implement children
List<Widget> get children {
for (int i = 1; i < 11; i++) {
this.children.add(MyContainer(i));
}
return this.children;
}
}
Use the build-in Column widget and instantiate it like similar widgets: Column(), Text(), etc., instead of extending the class. Please refer to the official dart documentation here, to learn how to properly use the extends key word.
You can´t just add multiple widgets to Scaffold´s body, since it expects a single widget (e.g., a Column, Text or Container).
You can use a custom widget MyCustomColumn to configure your column (see code below), but you can also simply add a column to body and pass the List.generate method to its children property.
Here is a code example:
class MyCustomColumn extends StatelessWidget {
const MyCustomColumn ({ Key? key }) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(children: List.generate(11, (index) {
return MyContainer(i);}
),
);
}
}