LogoWidgetbook

Knob example

This code defines a use case for a hypothetical MyHomePage widget in the Widgetbook. The knobs provide an interactive way to adjust the widget's parameters in the Widgetbook user interface.

WidgetbookUseCase(
  name: 'Home Page',
  builder: (context) => MyHomePage(
    // Knobs are coming here
  ),
),

The WidgetbookUseCase takes a name and a builder function, which constructs a MyHomePage widget.

title: context.knobs.string(
  label: 'Title',
  initialValue: 'Title',
),

The title knob is a string that allows the user to modify the title parameter of the MyHomePage widget. The label is displayed in the user interface, and the initialValue is the value that the knob starts with.

incrementBy: context.knobs.doubleOrNull.slider(
  label: 'Increment By',
  min: 0,
  initialValue: 5,
  max: 10,
  divisions: 10,
).toInt() ?? 0,

The incrementBy knob is a doubleOrNull.slider knob that lets the user adjust a double value using a slider. The slider will have a range from min to max, divided into divisions number of parts. If the knob's value is null (i.e., the user hasn't set a value), it defaults to 0.

countLabel: context.knobs.stringOrNull(
  label: 'Count Label',
  initialValue: 'Current Count',
  description: 'This is the text that appears above the current count of increments',
),

The countLabel knob is a stringOrNull that allows the user to adjust the countLabel parameter of the MyHomePage widget. If the user doesn't set a value, the knob's value will be null.

iconData: context.knobs.list(
  label: 'Icon',
  options: [Icons.add, Icons.crop_square_sharp, Icons.circle]
),

The iconData knob is a list knob that allows the user to select an icon from a list of options.

showToolTip: context.knobs.boolean(
  label: 'Show Increment Tool Tip',
  description: 'This is the tooltip that is displayed when hovering over the increment button',
  initialValue: true,
),

The showToolTip knob is a boolean knob that lets the user toggle whether a tooltip should be shown when the increment button is hovered over.

The builder function ends, returning the MyHomePage widget with the parameters set according to the knobs' values. The WidgetbookUseCase also ends here.

Putting it all together#

import 'package:flutter/material.dart';
import 'package:widgetbook/widgetbook.dart';

void main() {
  runApp(const KnobsExample());
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    required this.title,
    this.incrementBy = 1,
    this.countLabel,
    this.iconData,
    this.showToolTip = true,
    this.color = Colors.blue
    this.duration = Duration.zero,
    this.dateTime,
    super.key,
  });

  final String title;
  final int incrementBy;
  final String? countLabel;
  final IconData? iconData;
  final bool showToolTip;
  final Color color;
  final Duration duration;
  final DateTime? dateTime;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter += widget.incrementBy;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              widget.countLabel ??
                  'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            Text(
              color.value.toRadixString(16),
              style: TextStyle(
                color: color
              )
            ),
            Text(
              '${widget.duration}',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            Text(
              widget.dateTime?.toSimpleFormat() ?? '-',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: widget.showToolTip ? 'Increment' : null,
        child: Icon(widget.iconData ?? Icons.add),
      ),
    );
  }
}

class KnobsExample extends StatelessWidget {
  const KnobsExample({super.key});

  @override
  Widget build(BuildContext context) {
    final initialDate = DateTime.now();

    return Widgetbook.material(
      addons: [
        DeviceFrameAddon(
          devices: [
            Devices.ios.iPhoneSE,
            Devices.ios.iPhone13,
          ],
        ),
        TextScaleAddon(
          scales: [1, 2],
        ),
        MaterialThemeAddon(
          themes: [
            WidgetbookTheme(
              data: ThemeData.dark(),
              name: 'dark',
            ),
          ],
        ),
      ],
      directories: [
        WidgetbookCategory(
          name: 'Pages',
          children: [
            WidgetbookComponent(
              name: 'On boarding',
              useCases: [
                WidgetbookUseCase(
                  name: 'Home Page',
                  builder: (context) => MyHomePage(
                    title: context.knobs
                        .string(label: 'Title', initialValue: 'Title'),
                    incrementBy: context.knobs.doubleOrNull
                            .slider(
                              label: 'Increment By',
                              min: 0,
                              initialValue: 5,
                              max: 10,
                              divisions: 10,
                            )
                            ?.toInt() ??
                        0,
                    countLabel: context.knobs.stringOrNull(
                      label: 'Count Label',
                      initialValue: 'Current Count',
                      description:
                          'This is the text that appears above the current count of increments',
                    ),
                    iconData: context.knobs.list(
                      label: 'Icon',
                      options: [
                        Icons.add,
                        Icons.crop_square_sharp,
                        Icons.circle
                      ],
                    ),
                    showToolTip: context.knobs.boolean(
                      label: 'Show Increment Tool Tip',
                      description:
                          'This is the tooltip that is displayed when hovering over the increment button',
                      initialValue: true,
                    ),
                    color: context.knobs.color(
                      label: 'Change text color',
                      initialValue: Colors.blue,
                    ),
                    duration: context.knobs.duration(
                      label: 'Increment duration',
                      initialValue: const Duration(seconds: 5),
                    ),
                    dateTime: context.knobs.dateTimeOrNull(
                        // placing DateTime.now() here will cause the date time and
                        // the text field to be out of sync
                        initialValue: initialDate,
                        label: 'Select Date Time',
                        start: DateTime(initialDate.year - 1),
                        end: DateTime(initialDate.year + 1),
                    ),
                  ),
                ),
              ],
            ),
          ],
        ),
      ],
    );
  }
}

You can see an example of this and different knobs available here.