How to calculate the size of child widget inside customAppbar - flutter

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

Related

Flutter: Why the hashCodes of the following container widgets are changing eveytime I hot-reload the app (save the file)?

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;
}
}

How can i add textfield in text widget? - Flutter

I want to add textfield in a text widget.
like that:
I want to ___ textfield in a text widget.
You can use two seperate Text widgets and a TextField widget in between, all in a Row widget. like this:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: Center(
child: MyStatefulWidget(),
),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
#override
_State createState() => _State();
}
class _State extends State<MyStatefulWidget> {
bool isTextFieldEnabled = true;
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: [
Text('I want to'),
Container(
width: 200,
child: TextField(
enabled: isTextFieldEnabled,
),
),
Text('textfield in a text widget.'),
],
));
}
}

There are some parts that I don't understand well about Flutter's Key

I practiced after watching a video explaining Flutter's Key.
https://api.flutter.dev/flutter/foundation/Key-class.html
This video shows an example of changing the location of a container with a specific color. (About 1 minute and 50 seconds)
In the video, the statefulwidget says that without a key, the location will not change.
But I wrote the example code myself and confirmed that it worked without giving a key to the stateful widget.
I think I wrote the example code wrong. Below is the code I wrote.
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: KeyPractice(),
);
}
}
class StatefulColorfulTile extends StatefulWidget {
StatefulColorfulTile({#required this.color});
final Color color;
#override
_StatefulColorfulTileState createState() => _StatefulColorfulTileState();
}
class _StatefulColorfulTileState extends State<StatefulColorfulTile> {
#override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: widget.color,
);
}
}
class KeyPractice extends StatefulWidget {
#override
_KeyPracticeState createState() => _KeyPracticeState();
}
class _KeyPracticeState extends State<KeyPractice> {
List<Widget> tiles;
#override
void initState() {
super.initState();
tiles = [
StatefulColorfulTile(
color: Colors.blueAccent,
),
StatefulColorfulTile(
color: Colors.amber,
),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Row(
children: tiles,
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.autorenew,
),
onPressed: () {
setState(() {
tiles.insert(1, tiles.removeAt(0));
});
},
),
);
}
}
The above codes switch positions with each other.
What happens to the example of how the widget does not reposition each other when the stateful widget in the video does not assign keys?
And I understand that the key works only on the Stateful widget, does the Stateless use the key?
And I understood that Key only works with the Stateful widget. I wonder if the Stateless widget uses a key.
If I misunderstood, please teach me.
You're storing the color in the State of KeyPractice. The example they use stores it in the State of the child, in your case: StatefulColorfulTile.
Below is an example of the use of keys to correctly reposition widgets like you're trying to do. My example ended up very similar to what's shown on this medium article. Removing the keys here prevents the widgets from reflecting the color swap, but the use of the keys allows for the intended behavior.
import 'package:flutter/material.dart';
import 'dart:math';
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: KeyPractice(),
);
}
}
class StatefulColorfulTile extends StatefulWidget {
StatefulColorfulTile({Key key}) : super(key: key);
#override
_StatefulColorfulTileState createState() => _StatefulColorfulTileState();
}
class _StatefulColorfulTileState extends State<StatefulColorfulTile> {
final Color myColor = UniqueColorGenerator.getColor();
#override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: myColor,
);
}
}
class KeyPractice extends StatefulWidget {
#override
_KeyPracticeState createState() => _KeyPracticeState();
}
class _KeyPracticeState extends State<KeyPractice> {
List<Widget> tiles;
#override
void initState() {
super.initState();
tiles = [
StatefulColorfulTile(key: UniqueKey()),
StatefulColorfulTile(key: UniqueKey()),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Row(
children: tiles,
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.autorenew,
),
onPressed: () {
setState(() {
tiles.insert(1, tiles.removeAt(0));
});
},
),
);
}
}
class UniqueColorGenerator {
static Random random = new Random();
static Color getColor() {
return Color.fromARGB(255, random.nextInt(255), random.nextInt(255), random.nextInt(255));
}
}

Can I change the body of a widget using setState?

My application has scaffold.
But I want to change only the body of scaffold.
Normally I use setState() to change the state, but in this case, How can I use setState() or I can do some other way??
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
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();
}
void onTapped() {
print ("tapped");
// I want to change only body of Scaffold like this
// body: new Text("new body");
};
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body:
GestureDetector(
onTap: () => onTapped(),
child:Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
),
);
}
}
If you want to just setState within the body of the scaffold, make the body a stateful widget and call setState within that widget. You can define your own stateless and stateful widgets by extending StatelessWidget or StatefulWidget. It is useful to define a particular thing as its own widget instead of just as a method that returns a widget because of how Flutter compartmentalizes the rebuilding process. If the body of the scaffold is its own widget, only that widget will be rebuilt when you call setState. If you do what the other answer suggests, you will rebuild MyHomePage, which includes the scaffold. On the other hand, if you define a stateful widget with a smaller scope, and then call setState() within that widget, only the widget with the smaller scope will be rebuilt.
For example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
print('scaffold rebuilt');
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ScaffoldBody(),
);
}
}
class ScaffoldBody extends StatefulWidget {
#override
_ScaffoldBodyState createState() => _ScaffoldBodyState();
}
class _ScaffoldBodyState extends State<ScaffoldBody> {
int timesTapped = 0;
void onTapped() {
setState(() {
timesTapped++;
});
}
#override
Widget build(BuildContext context) {
print('scaffold body rebuilt');
return GestureDetector(
onTap: onTapped,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times: $timesTapped',
),
],
),
),
);
}
}
You can create a variable Widget _scaffoldBody; to hold the current Scaffold body.
You set an initial value to it, and then call setState when you need to change the body.
Something like this:
class _MyHomePageState extends State<MyHomePage> {
Widget _scaffoldBody;
#override
void initState(){
// Initialize it with the first body you want visible.
_scaffoldBody = GestureDetector(
onTap: () => onTapped(),
child:Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
);
}
// Note: move the onTapped method inside the state so you can call setState;
void onTapped()
// Call setState changing the body
setState((){
_scaffoldBody = Text("new body");
});
};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _scaffoldBody,
);
}
}

show/hide a widget without recreating it

Let's say I have 2 cards and one is shown on screen at a time. I have a button that replaces the current card with other cards. Now assume that there is some data on card 1 and some data on card 2 and I don't want to destroy the data on each of them or I don't want to rebuild any of them again.
I tried using Stack Widget and overlapping one on top of others with a boolean on the top card. The value of this boolean is reversed by calling setstate when the button is pressed. The issue is as soon as I press the button, the new card rebuilds all over again and then shown or initState is called again, which I don't want. Any Solution?
EDIT: Sample Code:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var toggleFlag = false;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: toggleFlag
? CustomWidget(color: Colors.blue)
: CustomWidget(color: Colors.red),
),
floatingActionButton: new FloatingActionButton(
onPressed: _toggleCard,
tooltip: 'Increment',
child: new Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
void _toggleCard() {
setState(() {
toggleFlag = !toggleFlag;
});
}
}
class CustomWidget extends StatefulWidget {
var color;
CustomWidget({this.color});
#override
State<StatefulWidget> createState() {
return new MyState();
}
}
class MyState extends State<CustomWidget> {
#override //I don't want this to be called again and again
Widget build(BuildContext context) {
return new Container(
height: 100.0,
width: 100.0,
color: widget.color,
);
}
}
1-Solution:
You have an array of widgets like this
final widgetList[widget1(), widget2()]
int currentIndex = 0;
IndexedStack (
   index: currentIndex,
   children: widgetList,
 ));
2-Solution:
With the Stack widget
int currentIndex = 0;
Stack(
children: [
Offstage(
offstage: currentIndex != 0,
child: bodyList[0],
),
Offstage(
offstage: currentIndex != 1,
child: bodyList[1],
),
Offstage(
offstage: currentIndex != 2,
child: bodyList[2],
),
],
)
3-Solution:
You need to add this to your stateful widget state
AutomaticKeepAliveClientMixin <Widgetname> like this
class _WidgetState extends State <Widgetname> with AutomaticKeepAliveClientMixin <Widgetname> {
#override
   bool get wantKeepAlive => true;
}
just wrap that Widget inside a Visibility widget then set "maintainSate" to true
Visibility(
visible: toggleFlag,
maintainState: true,
child: const CustomWidget(),
)
Stateless widgets are always considered to be perishable. If you want to preserve state, use a StatefulWidget and a State subclass.