blob: a4f52b32ebc5fb0a789bd4c64d13d8bd134265f5 [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
chunhtaiefb93682022-05-24 13:53:55 -07005import 'package:flutter/material.dart';
6import 'package:flutter/rendering.dart';
7
Greg Spencere3bc8ef2023-04-04 13:34:29 -07008/// Flutter code sample for [SelectionContainer].
chunhtaiefb93682022-05-24 13:53:55 -07009
Greg Spencere3bc8ef2023-04-04 13:34:29 -070010void main() => runApp(const SelectionContainerExampleApp());
chunhtaiefb93682022-05-24 13:53:55 -070011
Greg Spencere3bc8ef2023-04-04 13:34:29 -070012class SelectionContainerExampleApp extends StatelessWidget {
13 const SelectionContainerExampleApp({super.key});
chunhtaiefb93682022-05-24 13:53:55 -070014
15 @override
16 Widget build(BuildContext context) {
17 return MaterialApp(
chunhtaiefb93682022-05-24 13:53:55 -070018 home: SelectionArea(
19 child: Scaffold(
Greg Spencere3bc8ef2023-04-04 13:34:29 -070020 appBar: AppBar(title: const Text('SelectionContainer Sample')),
Michael Goderbauerb0f17142023-02-02 11:33:57 -080021 body: const Center(
chunhtaiefb93682022-05-24 13:53:55 -070022 child: SelectionAllOrNoneContainer(
23 child: Column(
24 mainAxisAlignment: MainAxisAlignment.center,
Michael Goderbauerb0f17142023-02-02 11:33:57 -080025 children: <Widget>[
chunhtaiefb93682022-05-24 13:53:55 -070026 Text('Row 1'),
27 Text('Row 2'),
28 Text('Row 3'),
29 ],
30 ),
31 ),
32 ),
33 ),
34 ),
35 );
36 }
37}
38
39class SelectionAllOrNoneContainer extends StatefulWidget {
Greg Spencere3bc8ef2023-04-04 13:34:29 -070040 const SelectionAllOrNoneContainer({super.key, required this.child});
chunhtaiefb93682022-05-24 13:53:55 -070041
42 final Widget child;
43
44 @override
45 State<StatefulWidget> createState() => _SelectionAllOrNoneContainerState();
46}
47
48class _SelectionAllOrNoneContainerState extends State<SelectionAllOrNoneContainer> {
49 final SelectAllOrNoneContainerDelegate delegate = SelectAllOrNoneContainerDelegate();
50
51 @override
52 void dispose() {
53 delegate.dispose();
54 super.dispose();
55 }
56
57 @override
58 Widget build(BuildContext context) {
59 return SelectionContainer(
60 delegate: delegate,
61 child: widget.child,
62 );
63 }
64}
65
66class SelectAllOrNoneContainerDelegate extends MultiSelectableSelectionContainerDelegate {
67 Offset? _adjustedStartEdge;
68 Offset? _adjustedEndEdge;
69 bool _isSelected = false;
70
71 // This method is called when newly added selectable is in the current
72 // selected range.
73 @override
74 void ensureChildUpdated(Selectable selectable) {
75 if (_isSelected) {
76 dispatchSelectionEventToChild(selectable, const SelectAllSelectionEvent());
77 }
78 }
79
80 @override
81 SelectionResult handleSelectWord(SelectWordSelectionEvent event) {
82 // Treat select word as select all.
83 return handleSelectAll(const SelectAllSelectionEvent());
84 }
85
86 @override
87 SelectionResult handleSelectionEdgeUpdate(SelectionEdgeUpdateEvent event) {
88 final Rect containerRect = Rect.fromLTWH(0, 0, containerSize.width, containerSize.height);
89 final Matrix4 globalToLocal = getTransformTo(null)..invert();
90 final Offset localOffset = MatrixUtils.transformPoint(globalToLocal, event.globalPosition);
91 final Offset adjustOffset = SelectionUtils.adjustDragOffset(containerRect, localOffset);
92 if (event.type == SelectionEventType.startEdgeUpdate) {
93 _adjustedStartEdge = adjustOffset;
94 } else {
95 _adjustedEndEdge = adjustOffset;
96 }
97 // Select all content if the selection rect intercepts with the rect.
98 if (_adjustedStartEdge != null && _adjustedEndEdge != null) {
99 final Rect selectionRect = Rect.fromPoints(_adjustedStartEdge!, _adjustedEndEdge!);
100 if (!selectionRect.intersect(containerRect).isEmpty) {
101 handleSelectAll(const SelectAllSelectionEvent());
102 } else {
103 super.handleClearSelection(const ClearSelectionEvent());
104 }
105 } else {
106 super.handleClearSelection(const ClearSelectionEvent());
107 }
108 return SelectionUtils.getResultBasedOnRect(containerRect, localOffset);
109 }
110
111 @override
112 SelectionResult handleClearSelection(ClearSelectionEvent event) {
113 _adjustedStartEdge = null;
114 _adjustedEndEdge = null;
115 _isSelected = false;
116 return super.handleClearSelection(event);
117 }
118
119 @override
120 SelectionResult handleSelectAll(SelectAllSelectionEvent event) {
121 _isSelected = true;
122 return super.handleSelectAll(event);
123 }
124}