getAdaptiveButtons static method

Iterable<Widget> getAdaptiveButtons(
  1. BuildContext context,
  2. List<ContextMenuButtonItem> buttonItems
)

Returns a List of Widgets generated by turning buttonItems into the default context menu buttons for the current platform.

This is useful when building a text selection toolbar with the default button appearance for the given platform, but where the toolbar and/or the button actions and labels may be custom.

This sample demonstrates how to use getAdaptiveButtons to generate default button widgets in a custom toolbar.

To see it in action, copy and run this code snippet on DartPad.

// This example demonstrates how to create a custom toolbar that retains the
// look of the default buttons for the current platform.

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:material_ui/material_ui.dart';

void main() => runApp(const EditableTextToolbarBuilderExampleApp());

class EditableTextToolbarBuilderExampleApp extends StatefulWidget {
  const EditableTextToolbarBuilderExampleApp({super.key});

  @override
  State<EditableTextToolbarBuilderExampleApp> createState() =>
      _EditableTextToolbarBuilderExampleAppState();
}

class _EditableTextToolbarBuilderExampleAppState
    extends State<EditableTextToolbarBuilderExampleApp> {
  final TextEditingController _controller = TextEditingController(
    text:
        'Right click (desktop) or long press (mobile) to see the menu with a custom toolbar.',
  );

  @override
  void initState() {
    super.initState();
    // On web, disable the browser's context menu since this example uses a custom
    // Flutter-rendered context menu.
    if (kIsWeb) {
      BrowserContextMenu.disableContextMenu();
    }
  }

  @override
  void dispose() {
    if (kIsWeb) {
      BrowserContextMenu.enableContextMenu();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Custom toolbar, default-looking buttons'),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              const SizedBox(height: 20.0),
              TextField(
                controller: _controller,
                contextMenuBuilder:
                    (
                      BuildContext context,
                      EditableTextState editableTextState,
                    ) {
                      return _MyTextSelectionToolbar(
                        anchor:
                            editableTextState.contextMenuAnchors.primaryAnchor,
                        // getAdaptiveButtons creates the default button widgets for
                        // the current platform.
                        children:
                            AdaptiveTextSelectionToolbar.getAdaptiveButtons(
                              context,
                              // These buttons just close the menu when clicked.
                              <ContextMenuButtonItem>[
                                ContextMenuButtonItem(
                                  label: 'One',
                                  onPressed: () =>
                                      ContextMenuController.removeAny(),
                                ),
                                ContextMenuButtonItem(
                                  label: 'Two',
                                  onPressed: () =>
                                      ContextMenuController.removeAny(),
                                ),
                                ContextMenuButtonItem(
                                  label: 'Three',
                                  onPressed: () =>
                                      ContextMenuController.removeAny(),
                                ),
                                ContextMenuButtonItem(
                                  label: 'Four',
                                  onPressed: () =>
                                      ContextMenuController.removeAny(),
                                ),
                                ContextMenuButtonItem(
                                  label: 'Five',
                                  onPressed: () =>
                                      ContextMenuController.removeAny(),
                                ),
                              ],
                            ).toList(),
                      );
                    },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

/// A simple, yet totally custom, text selection toolbar.
///
/// Displays its children in a scrollable grid.
class _MyTextSelectionToolbar extends StatelessWidget {
  const _MyTextSelectionToolbar({required this.anchor, required this.children});

  final Offset anchor;
  final List<Widget> children;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned(
          top: anchor.dy,
          left: anchor.dx,
          child: Container(
            width: 200.0,
            height: 200.0,
            color: Colors.cyanAccent.withValues(alpha: 0.5),
            child: GridView.count(
              padding: const .all(12.0),
              crossAxisCount: 2,
              children: children,
            ),
          ),
        ),
      ],
    );
  }
}

See also:

  • CupertinoAdaptiveTextSelectionToolbar.getAdaptiveButtons, which is the Cupertino equivalent of this class and builds only the Cupertino buttons.

Implementation

// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/context_menu/editable_text_toolbar_builder.2.dart#body}
///
/// </callout-box>
///
/// See also:
///
/// * [CupertinoAdaptiveTextSelectionToolbar.getAdaptiveButtons], which is the
///   Cupertino equivalent of this class and builds only the Cupertino
///   buttons.
static Iterable<Widget> getAdaptiveButtons(
  BuildContext context,
  List<ContextMenuButtonItem> buttonItems,
) {
  switch (Theme.of(context).platform) {
    case TargetPlatform.iOS:
      return buttonItems.map((ContextMenuButtonItem buttonItem) {
        return CupertinoTextSelectionToolbarButton.buttonItem(buttonItem: buttonItem);
      });
    case TargetPlatform.fuchsia:
    case TargetPlatform.android:
      final buttons = <Widget>[];
      for (var i = 0; i < buttonItems.length; i++) {
        final ContextMenuButtonItem buttonItem = buttonItems[i];
        buttons.add(
          TextSelectionToolbarTextButton(
            padding: TextSelectionToolbarTextButton.getPadding(i, buttonItems.length),
            onPressed: buttonItem.onPressed,
            alignment: AlignmentDirectional.centerStart,
            child: Text(getButtonLabel(context, buttonItem)),
          ),
        );
      }
      return buttons;
    case TargetPlatform.linux:
    case TargetPlatform.windows:
      return buttonItems.map((ContextMenuButtonItem buttonItem) {
        return DesktopTextSelectionToolbarButton.text(
          context: context,
          onPressed: buttonItem.onPressed,
          text: getButtonLabel(context, buttonItem),
        );
      });
    case TargetPlatform.macOS:
      return buttonItems.map((ContextMenuButtonItem buttonItem) {
        return CupertinoDesktopTextSelectionToolbarButton.text(
          onPressed: buttonItem.onPressed,
          text: getButtonLabel(context, buttonItem),
        );
      });
  }
}