In Flutter, is there a simple way to create a Widget's subclass, which modifies its default parameters?
Let's say I want to create a ShadedContainer
, which always has the same shadow decoration, but besides that, replicates all of Container
's behaviour.
The following simplified code works:
import 'package:flutter/material.dart';
class ShadedContainer extends StatelessWidget {
final Widget? child;
final double? width;
final double? height;
// private
final Decoration _decoration;
static const _boxShadow = [
BoxShadow(
color: Color(0x60000000),
offset: Offset(5, 5),
blurRadius: 7,
spreadRadius: 1,
),
];
// constructor
ShadedContainer({
Key? key,
this.width,
this.height,
this.child,
BoxDecoration? decoration,
}) : _decoration = (decoration == null)
? const BoxDecoration(
boxShadow: _boxShadow,
)
: BoxDecoration(
boxShadow: _boxShadow,
color: decoration.color,
border: decoration.border,
borderRadius: decoration.borderRadius,
),
super(key: key);
// builder
@override
Widget build(BuildContext context) {
return Container(
decoration: _decoration,
width: width,
height: height,
child: child,
);
}
}
This really doesn't seem optimal. I have not replicated all of the Container's parameters, and it is quite verbose already.
Is there a way to extend Container directly, instead of creating a new Widget from scratch (and without copying most of Container's source code... hence opening the door to future updates/fixes issues on that Widget)?
Thanks!
CodePudding user response:
There absolutely is a way to do this. In fact the first time I came across this idea of extending a class was on bloclibrary.dev/
This is from the default Counter app built using the bloc library
import 'package:flutter/material.dart';
import 'counter/counter.dart';
/// {@template counter_app}
/// A [MaterialApp] which sets the `home` to [CounterPage].
/// {@endtemplate}
class CounterApp extends MaterialApp {
/// {@macro counter_app}
const CounterApp({Key? key}) : super(key: key, home: const CounterPage());
}
I could extend the same logic to ShadedContainer. Based on your question a shaded container extends a container
class ShadedContainer extends Container {
ShadedContainer(
{Decoration? decoration, double? width, double? height, Widget? child})
: super(
width: width,
height: height,
child: child,
decoration: decoration ??
BoxDecoration(boxShadow: [
BoxShadow(
color: Color(0x60000000),
offset: Offset(5, 5),
blurRadius: 7,
spreadRadius: 1,
),
]));
}
It can then be used this way
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
darkTheme: ThemeData.dark(),
theme: ThemeData.light(),
home: Scaffold(
appBar: AppBar(title: Text('Shaded Container')),
body: Center(
child: ShadedContainer(
width: 100,
height: 100,
child: Center(child: Text('Extending')),
)),
),
debugShowCheckedModeBanner: false,
);
}
}