// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// Flutter code sample for [SelectionArea]. void main() => runApp(const SelectionAreaSelectionListenerExampleApp()); class SelectionAreaSelectionListenerExampleApp extends StatelessWidget { const SelectionAreaSelectionListenerExampleApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple)), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { final SelectionListenerNotifier _selectionNotifier = SelectionListenerNotifier(); SelectableRegionSelectionStatus? _selectableRegionStatus; void _handleOnSelectionStateChanged(SelectableRegionSelectionStatus status) { setState(() { _selectableRegionStatus = status; }); } @override void dispose() { _selectionNotifier.dispose(); _selectableRegionStatus = null; super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Center( child: Column( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ for (final (int? offset, String label) in <(int? offset, String label)>[ ( _selectionNotifier.registered ? _selectionNotifier.selection.range?.startOffset : null, 'StartOffset', ), ( _selectionNotifier.registered ? _selectionNotifier.selection.range?.endOffset : null, 'EndOffset', ), ]) Text('Selection $label: $offset'), Text( 'Selection Status: ${_selectionNotifier.registered ? _selectionNotifier.selection.status : 'SelectionListenerNotifier not registered.'}', ), Text('Selectable Region Status: $_selectableRegionStatus'), ], ), const SizedBox(height: 15.0), SelectionArea( child: MySelectableText( selectionNotifier: _selectionNotifier, onChanged: _handleOnSelectionStateChanged, ), ), ], ), ), ); } } class MySelectableText extends StatefulWidget { const MySelectableText({super.key, required this.selectionNotifier, required this.onChanged}); final SelectionListenerNotifier selectionNotifier; final ValueChanged onChanged; @override State createState() => _MySelectableTextState(); } class _MySelectableTextState extends State { ValueListenable? _selectableRegionScope; void _handleOnSelectableRegionChanged() { if (_selectableRegionScope == null) { return; } widget.onChanged.call(_selectableRegionScope!.value); } @override void didChangeDependencies() { super.didChangeDependencies(); _selectableRegionScope?.removeListener(_handleOnSelectableRegionChanged); _selectableRegionScope = SelectableRegionSelectionStatusScope.maybeOf(context); _selectableRegionScope?.addListener(_handleOnSelectableRegionChanged); } @override void dispose() { _selectableRegionScope?.removeListener(_handleOnSelectableRegionChanged); _selectableRegionScope = null; super.dispose(); } @override Widget build(BuildContext context) { return SelectionListener( selectionNotifier: widget.selectionNotifier, child: const Text('This is some text under a SelectionArea that can be selected.'), ); } }