Home > Software engineering >  Create a Flutter Widget sub class
Create a Flutter Widget sub class

Time:07-24

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/

enter image description here

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,
        );
      }
    }
  • Related