// 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. /// Flutter code sample for [SelectionContainer]. import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); static const String _title = 'Flutter Code Sample'; @override Widget build(BuildContext context) { return MaterialApp( title: _title, home: SelectionArea( child: Scaffold( appBar: AppBar(title: const Text(_title)), body: Center( child: SelectionAllOrNoneContainer( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: const [ Text('Row 1'), Text('Row 2'), Text('Row 3'), ], ), ), ), ), ), ); } } class SelectionAllOrNoneContainer extends StatefulWidget { const SelectionAllOrNoneContainer({ super.key, required this.child }); final Widget child; @override State createState() => _SelectionAllOrNoneContainerState(); } class _SelectionAllOrNoneContainerState extends State { final SelectAllOrNoneContainerDelegate delegate = SelectAllOrNoneContainerDelegate(); @override void dispose() { delegate.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return SelectionContainer( delegate: delegate, child: widget.child, ); } } class SelectAllOrNoneContainerDelegate extends MultiSelectableSelectionContainerDelegate { Offset? _adjustedStartEdge; Offset? _adjustedEndEdge; bool _isSelected = false; // This method is called when newly added selectable is in the current // selected range. @override void ensureChildUpdated(Selectable selectable) { if (_isSelected) { dispatchSelectionEventToChild(selectable, const SelectAllSelectionEvent()); } } @override SelectionResult handleSelectWord(SelectWordSelectionEvent event) { // Treat select word as select all. return handleSelectAll(const SelectAllSelectionEvent()); } @override SelectionResult handleSelectionEdgeUpdate(SelectionEdgeUpdateEvent event) { final Rect containerRect = Rect.fromLTWH(0, 0, containerSize.width, containerSize.height); final Matrix4 globalToLocal = getTransformTo(null)..invert(); final Offset localOffset = MatrixUtils.transformPoint(globalToLocal, event.globalPosition); final Offset adjustOffset = SelectionUtils.adjustDragOffset(containerRect, localOffset); if (event.type == SelectionEventType.startEdgeUpdate) { _adjustedStartEdge = adjustOffset; } else { _adjustedEndEdge = adjustOffset; } // Select all content if the selection rect intercepts with the rect. if (_adjustedStartEdge != null && _adjustedEndEdge != null) { final Rect selectionRect = Rect.fromPoints(_adjustedStartEdge!, _adjustedEndEdge!); if (!selectionRect.intersect(containerRect).isEmpty) { handleSelectAll(const SelectAllSelectionEvent()); } else { super.handleClearSelection(const ClearSelectionEvent()); } } else { super.handleClearSelection(const ClearSelectionEvent()); } return SelectionUtils.getResultBasedOnRect(containerRect, localOffset); } @override SelectionResult handleClearSelection(ClearSelectionEvent event) { _adjustedStartEdge = null; _adjustedEndEdge = null; _isSelected = false; return super.handleClearSelection(event); } @override SelectionResult handleSelectAll(SelectAllSelectionEvent event) { _isSelected = true; return super.handleSelectAll(event); } }