How to access parent widget inside child widget? - flutter

I have a widget:
class MyWidget extends StatelessWidget {
final Color? color;
final EdgeInsetsGeometry? padding;
final Widget child;
// ... many more properties
const MyWidget({
super.key,
this.color = Colors.blue,
this.padding = const EdgeInsets.all(4),
required this.child,
});
#override
Widget build(BuildContext context) {
return Container(
color: color,
padding: padding,
child: child,
);
}
}
I also have another widget which wraps the above widget in SliverToBoxAdapter like this:
class MySliverWidget extends MyWidget {
MySliverWidget({
super.color,
super.padding,
required super.child,
// ... many more properties
});
#override
Widget build(BuildContext context) {
// Unable to use "child: super".
return SliverToBoxAdapter(child: super);
}
}
But the problem is I am unable to use the parent widget (MyWidget) instance using super inside the child widget (MySliverWidget).
So, the question is how do I access MyWidget instance inside MySliverWidget?
Note:
In MySliverWidget.build() method, I don't want to use child: MyWidget(...) and pass all the parameters to it (which is redundant).
I also don't to simply use SliverToBoxAdapter(child: MyWidget(...)) instead of having a MySliverWidget in the first place.

Maybe like this :
return SliverToBoxAdapter(child: super.build(context));

Related

Does dart/flutter have the functionality to set UI properties on widgets at a class level?

Similar to using css and html. Goal would be to have a single file where we can set the color size or whatever other property for the Column, or DropDownMenu class and not have to repeat for every instance of the class.
Try the following code:
class CustomColumn extends StatelessWidget {
const CustomColumn({super.key, required this.children});
final List<Widget> children;
#override
Widget build(BuildContext context) {
return Column(
// You can style your Column here
children: children,
);
}
}
class CustomDropdownButton extends StatelessWidget {
const CustomDropdownButton({super.key, required this.items, required this.onChanged});
final List<DropdownMenuItem> items;
final void Function(dynamic) onChanged;
#override
Widget build(BuildContext context) {
return DropdownButton(
items: items,
onChanged: onChanged,
// You can style your DropdownButton here
);
}
}

Substitute a child of a widget by another widget / optionally wrapping a widget

Is it possible to "merge" two widgets together? I want to build an OptionalWrapper component, that wraps a widget by another widget only if a condition is matched.
The usage should look something like this, I provide a child and if the showWrapper condition is true, this child is put as the child of the wrapper widget.
OptionalWrapper(
showWrapper: !isSmallScreen(context),
wrapper: Padding(
padding: const EdgeInsets.only(top: 16.0),
child: // <-- Here should the child be rendered
),
child: Text("Hello"),
),
of course I could do something like this:
!isSmallScreen(context) ? Padding(
padding: const EdgeInsets.all(16.0),
child: Text("Hello"),
) : Text("Hello"),
But here I declare my Text widget twice which I want to avoid.
The implementation would look like this:
import 'package:flutter/material.dart';
class OptionalWrapper extends StatelessWidget {
final bool showWrapper;
final Widget wrapper;
final Widget child;
const OptionalWrapper({
Key? key,
required this.showWrapper,
required this.wrapper,
required this.child,
}) : super(key: key);
#override
Widget build(BuildContext context) {
if (showWrapper) {
// return the wrapper widget but subject child as child of the wrapper widget
} else {
return child;
}
}
}
You can create builder method like
import 'package:flutter/material.dart';
class OptionalWrapper extends StatelessWidget {
final bool showWrapper;
final Widget Function(Widget) wrapper;
final Widget child;
const OptionalWrapper({
Key? key,
required this.showWrapper,
required this.wrapper,
required this.child,
}) : super(key: key);
#override
Widget build(BuildContext context) {
if (showWrapper) {
return wrapper(child);
} else {
return child;
}
}
}
You can make the padding as EdgeInsects.zero if the condition fails
Padding(
padding: !isSmallScreen(context)?const EdgeInsets.all(16.0): EdgeInsects.zero,
child: Text("Hello"),

If I use StatefulWidget in StatelessWidget, each StatefulWidget perform like Stateless Widget?

I use Widgets Like this (image). How performed they are?
A Stateful widget will perform exactly like a Stateless widget unless you mutate the state using setState method. The only time UI is rebuilt is when your run the setState((){}) method inside the Stateful widget.
Sample setState example from documentation.
class Bird extends StatefulWidget {
const Bird({
Key? key,
this.color = const Color(0xFFFFE306),
this.child,
}) : super(key: key);
final Color color;
final Widget? child;
#override
State<Bird> createState() => _BirdState();
}
class _BirdState extends State<Bird> {
double _size = 1.0;
void grow() {
setState(() { _size += 0.1; });
}
#override
Widget build(BuildContext context) {
return Container(
color: widget.color,
transform: Matrix4.diagonal3Values(_size, _size, 1.0),
child: widget.child,
);
}
}
Reference: Stateful Widgets - LINK
You can try and learn about Stateful widgets in the above documentation link.

Flutter optionally include / exclude parent widget in widget tree

I have this widget tree
return Container(
color: Colors.blue,
child: Container(
child: Text("Child"),
),
);
Is there a way to remove a parent widget from the tree or conditionally include it?
For example if a state variable such as includeBlueContainer was false, I would like to not render the blue container (but show everything else).
I couldn't achieve an optionally include reusable widget but I've been using this pattern which does achieve what I wanted to achieve. I haven't given this a great amount of thought but I still feel there is a better solution somewhere.
class MyContainer extends StatelessWidget {
final Widget child;
final bool isIncluded;
MyContainer({this.child, this.isIncluded = true});
Widget build(BuildContext context) {
if (!isIncluded) return child;
return Container(
color: Colors.blue,
child: child,
);
}
}
Edit: I made a package out of this: https://pub.dev/packages/conditional_parent_widget
Which you can use like:
import 'package:flutter/widgets.dart';
import 'package:conditional_parent_widget/conditional_parent_widget.dart';
// ...
return ConditionalParentWidget(
condition: includeBlueContainer,
child: Text("Child"),
parentBuilder: (Widget child) => Container(
color: Colors.blue,
child: child,
),
);
Internally it is just:
import 'package:flutter/widgets.dart';
class ConditionalParentWidget extends StatelessWidget {
const ConditionalParentWidget({
Key? key,
required this.condition,
required this.child,
required this.parentBuilder,
}) : super(key: key);
final Widget child;
final bool condition;
final Widget Function(Widget child) parentBuilder;
#override
Widget build(BuildContext context) {
return condition ? this.parentBuilder(this.child) : this.child;
}
}

Should "const" for widgets need to be used only in stateful widgets?

It's clear that in StatefulWidget if state changes then const Text('...') will not be rebuild.
class _SomeWidgetState extends State<SomeWidget> {
#override
Widget build(BuildContext context) {
return const Text('Some Static Text'); // doesn't rebuild
}
}
But, my question is: Is there any benefits of using const in StatelessWidget?
class ListItem extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const Text('Some Static Text') // Is `const` useful here?
}
}
Yes, it is useful.
Const constructors inside build is useful for all kinds of widgets, including StatelessWidget and other less common ones like InheritedWidget or RenderObjectWidget.
Bear in mind that all widgets may take parameters, so you may have:
class MyStateless extends StatelessWidget {
const MyStateless({Key key, this.count}): super(key: key);
final int count;
#override
Widget build(BuildContext context) {
return Row(
children: [
Text('$count'),
const Text('static text'),
],
);
}
}
In that situation, your stateless widget may rebuild with a different parameter, like going from:
MyStateless(count: 0);
to:
MyStateless(count: 42);
In that situation, using const Text('static text') will not cause this text to rebuild.