selectable 0.2.2 copy "selectable: ^0.2.2" to clipboard
selectable: ^0.2.2 copied to clipboard

outdated

A Flutter widget that enables text selection over all the text widgets it contains.

example/lib/main.dart

import 'dart:async';
import 'dart:math' as math;

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

import 'package:selectable/selectable.dart';

// ignore_for_file: avoid_print

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _scrollController = ScrollController();
  final _selectionController = SelectableController();
  var _isTextSelected = false;
  late Timer _timer;

  @override
  void initState() {
    super.initState();
    _selectionController.addListener(() {
      if (_isTextSelected != _selectionController.isTextSelected) {
        _isTextSelected = _selectionController.isTextSelected;
        // print(_isTextSelected ? 'Text is selected' : 'Text is not selected');
        if (mounted) setState(() {});
      }
      // if (_selectionController.rects != null) {
      //   print('selection rects: ${_selectionController.rects}');
      // }
    });

    _timer = Timer.periodic(const Duration(seconds: 1), (_) {
      final text = _selectionController.getContainedText();
      if (text.isNotEmpty) {
        final i = random(max: text.length);
        if (_selectionController.selectWordAtIndex(i, key: 1)) {
          // print('selected word at $i');
        } else {
          // print('failed to select word at $i');
        }
      }
    });
  }

  @override
  void dispose() {
    _timer.cancel();
    _selectionController.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  var _showSelection = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        controller: _scrollController,
        slivers: [
          const SliverAppBar(
            pinned: true,
            expandedHeight: 100,
            flexibleSpace: FlexibleSpaceBar(title: Text('Selectable Example')),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => Selectable(
                selectWordOnDoubleTap: true,
                selectionController: _selectionController,
                scrollController: _scrollController,
                // selectionColor: Colors.orange.withAlpha(75),
                // showSelection: _showSelection,
                popupMenuItems: [
                  SelectableMenuItem(type: SelectableMenuItemType.copy),
                  SelectableMenuItem(
                    title: 'Foo! :)',
                    isEnabled: (controller) {
                      // print('SelectableMenuItem Foo, isEnabled, selected text:
                      // ${controller!.text}');
                      return controller!.isTextSelected;
                    },
                    handler: (controller) {
                      showDialog<void>(
                        context: context,
                        barrierDismissible: true,
                        builder: (builder) {
                          return AlertDialog(
                            contentPadding: EdgeInsets.zero,
                            content: Container(
                              padding: const EdgeInsets.all(16),
                              child: Text(controller!.getSelection()!.text!),
                            ),
                            shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(8)),
                          );
                        },
                      );
                      return true;
                    },
                  ),
                ],
                child: Container(
                  padding: const EdgeInsets.all(20),
                  child: Column(
                    //mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Double-tap or long press on a word to select it, then drag '
                        'the selection controls to change the selection.',
                        style: Theme.of(context).textTheme.headline5,
                      ),
                      FloatColumn(
                        children: [
                          const SizedBox(height: 16),
                          Floatable(
                              float: FCFloat.end,
                              clear: FCClear.both,
                              padding:
                                  const EdgeInsetsDirectional.only(start: 16),
                              maxWidthPercentage: 0.333,
                              child:
                                  Container(height: 150, color: Colors.orange)),
                          WrappableText(
                            text: TextSpan(
                              text: 'Indent Example',
                              style: Theme.of(context).textTheme.headline4,
                            ),
                          ),
                          const WrappableText(
                            indent: 40,
                            text: TextSpan(text: text1, style: textStyle2),
                            textAlign: TextAlign.justify,
                          ),
                          const SizedBox(height: 16),
                          Floatable(
                              float: FCFloat.start,
                              clear: FCClear.both,
                              padding: const EdgeInsetsDirectional.only(
                                  end: 16, top: 8),
                              maxWidthPercentage: 0.333,
                              child:
                                  Container(height: 150, color: Colors.blue)),
                          WrappableText(
                            text: TextSpan(
                              text: 'Hanging Indent Example',
                              style: Theme.of(context).textTheme.headline4,
                            ),
                          ),
                          const WrappableText(
                            indent: -40,
                            padding: EdgeInsets.only(left: 40),
                            text:
                                TextSpan(children: [_span], style: textStyle1),
                          ),
                        ],
                      ),
                      const SizedBox(height: 16),
                      const Text.rich(
                        _span,
                        style: textStyle2,
                        //style: Theme.of(context).textTheme.display1,
                      ),
                      const Text('\n\n\n'),
                    ],
                  ),
                ),
              ),
              childCount: 1,
            ),
          ),
        ],
      ),
      floatingActionButton: _isTextSelected
          ? FloatingActionButton.extended(
              onPressed: () {
                //Provider.of<Counter>(context, listen: false).increment();

                setState(() {
                  _showSelection = !_showSelection;
                  if (_showSelection) {
                    _selectionController.unhide();
                  } else {
                    _selectionController.hide();
                  }
                });

                // if (_selectionController.isTextSelected) {
                //   _selectionController.deselectAll();
                // }
              },
              //tooltip: 'Increment',
              //child: Icon(Icons.add),
              label: Text(_showSelection ? 'hide selection' : 'show selection'),
            )
          : null,
    );
  }
}

// cspell: disable
const text1 = 'Lorem ipsum dolor sit amet, consectetur—adipiscing elit, sed '
    'do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim '
    'ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut '
    'aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit '
    'in voluptate velit esse cillum dolore eu fugiat nulla pariatur. '
    'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui '
    'officia deserunt mollit anim id est laborum.';
const text2 = 'onsectetur adipiscing elit, sed do eiusmod tempor incididunt '
    'ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud '
    'exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. '
    'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum '
    'dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non '
    'proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';

const _span = TaggedTextSpan(
  tag: 'tag',
  children: <TextSpan>[
    TextSpan(style: TextStyle(color: Colors.red), text: 'Lor'),
    TextSpan(style: TextStyle(color: Colors.blue), text: 'em i'),
    TextSpan(style: TextStyle(color: Colors.green), text: 'psu'),
    TextSpan(style: TextStyle(color: Colors.red), text: 'm do'),
    TextSpan(style: TextStyle(color: Colors.blue), text: 'lor'),
    TextSpan(style: TextStyle(color: Colors.green), text: ' sit '),
    TextSpan(style: TextStyle(color: Colors.red), text: 'ame'),
    TextSpan(style: TextStyle(color: Colors.blue), text: 't, c'),
    TextSpan(text: text2),
  ],
);

const TextStyle textStyle1 = TextStyle(
  fontSize: 20,
  fontWeight: FontWeight.normal,
  height: 1.5,
);

const TextStyle textStyle2 = TextStyle(
  fontSize: 20,
  fontWeight: FontWeight.normal,
  height: 1.5,
  backgroundColor: Colors.transparent,
);

math.Random? _random;
const maxRandomInt = 0x100000000;

int random({int min = 0, required int max}) {
  assert(max > min);
  final safeRange = math.min(maxRandomInt, math.max(0, max - min));
  _random ??= math.Random();
  return _random!.nextInt(safeRange) + min;
}
69
likes
0
pub points
92%
popularity

Publisher

verified publisherronbooth.com

A Flutter widget that enables text selection over all the text widgets it contains.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

characters, collection, equatable, float_column, flutter, url_launcher

More

Packages that depend on selectable