blob: cd8a5034ce68debac1e6527eafff412fe1f2972b [file] [log] [blame]
chunhtaiefb93682022-05-24 13:53:55 -07001// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Michael Goderbauerb3085552022-12-20 16:03:21 -08005// Flutter code sample for [SelectionContainer].
chunhtaiefb93682022-05-24 13:53:55 -07006
7import 'package:flutter/material.dart';
8import 'package:flutter/rendering.dart';
9
10void main() => runApp(const MyApp());
11
12class MyApp extends StatelessWidget {
13 const MyApp({super.key});
14
15 static const String _title = 'Flutter Code Sample';
16
17 @override
18 Widget build(BuildContext context) {
19 return MaterialApp(
20 title: _title,
21 home: SelectionArea(
22 child: Scaffold(
23 appBar: AppBar(title: const Text(_title)),
Michael Goderbauerb0f17142023-02-02 11:33:57 -080024 body: const Center(
chunhtaiefb93682022-05-24 13:53:55 -070025 child: SelectionAllOrNoneContainer(
26 child: Column(
27 mainAxisAlignment: MainAxisAlignment.center,
Michael Goderbauerb0f17142023-02-02 11:33:57 -080028 children: <Widget>[
chunhtaiefb93682022-05-24 13:53:55 -070029 Text('Row 1'),
30 Text('Row 2'),
31 Text('Row 3'),
32 ],
33 ),
34 ),
35 ),
36 ),
37 ),
38 );
39 }
40}
41
42class SelectionAllOrNoneContainer extends StatefulWidget {
43 const SelectionAllOrNoneContainer({
44 super.key,
45 required this.child
46 });
47
48 final Widget child;
49
50 @override
51 State<StatefulWidget> createState() => _SelectionAllOrNoneContainerState();
52}
53
54class _SelectionAllOrNoneContainerState extends State<SelectionAllOrNoneContainer> {
55 final SelectAllOrNoneContainerDelegate delegate = SelectAllOrNoneContainerDelegate();
56
57 @override
58 void dispose() {
59 delegate.dispose();
60 super.dispose();
61 }
62
63 @override
64 Widget build(BuildContext context) {
65 return SelectionContainer(
66 delegate: delegate,
67 child: widget.child,
68 );
69 }
70}
71
72class SelectAllOrNoneContainerDelegate extends MultiSelectableSelectionContainerDelegate {
73 Offset? _adjustedStartEdge;
74 Offset? _adjustedEndEdge;
75 bool _isSelected = false;
76
77 // This method is called when newly added selectable is in the current
78 // selected range.
79 @override
80 void ensureChildUpdated(Selectable selectable) {
81 if (_isSelected) {
82 dispatchSelectionEventToChild(selectable, const SelectAllSelectionEvent());
83 }
84 }
85
86 @override
87 SelectionResult handleSelectWord(SelectWordSelectionEvent event) {
88 // Treat select word as select all.
89 return handleSelectAll(const SelectAllSelectionEvent());
90 }
91
92 @override
93 SelectionResult handleSelectionEdgeUpdate(SelectionEdgeUpdateEvent event) {
94 final Rect containerRect = Rect.fromLTWH(0, 0, containerSize.width, containerSize.height);
95 final Matrix4 globalToLocal = getTransformTo(null)..invert();
96 final Offset localOffset = MatrixUtils.transformPoint(globalToLocal, event.globalPosition);
97 final Offset adjustOffset = SelectionUtils.adjustDragOffset(containerRect, localOffset);
98 if (event.type == SelectionEventType.startEdgeUpdate) {
99 _adjustedStartEdge = adjustOffset;
100 } else {
101 _adjustedEndEdge = adjustOffset;
102 }
103 // Select all content if the selection rect intercepts with the rect.
104 if (_adjustedStartEdge != null && _adjustedEndEdge != null) {
105 final Rect selectionRect = Rect.fromPoints(_adjustedStartEdge!, _adjustedEndEdge!);
106 if (!selectionRect.intersect(containerRect).isEmpty) {
107 handleSelectAll(const SelectAllSelectionEvent());
108 } else {
109 super.handleClearSelection(const ClearSelectionEvent());
110 }
111 } else {
112 super.handleClearSelection(const ClearSelectionEvent());
113 }
114 return SelectionUtils.getResultBasedOnRect(containerRect, localOffset);
115 }
116
117 @override
118 SelectionResult handleClearSelection(ClearSelectionEvent event) {
119 _adjustedStartEdge = null;
120 _adjustedEndEdge = null;
121 _isSelected = false;
122 return super.handleClearSelection(event);
123 }
124
125 @override
126 SelectionResult handleSelectAll(SelectAllSelectionEvent event) {
127 _isSelected = true;
128 return super.handleSelectAll(event);
129 }
130}