resizable_sheet.dart
3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// ignore_for_file: always_put_control_body_on_new_line
import 'dart:math';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:sheet/sheet.dart';
/// A widget that allows to resize the child according to offset
/// of a sheet
///
/// See also:
///
/// * [Sheet], that uses this widget to allow resizable sheet child
class ResizableSheetChild extends SingleChildRenderObjectWidget {
const ResizableSheetChild({
super.key,
this.minExtent = 0,
required this.offset,
required Widget super.child,
required this.resizable,
});
final double minExtent;
final bool resizable;
final ViewportOffset offset;
@override
RenderResizableSheetChildBox createRenderObject(BuildContext context) {
return RenderResizableSheetChildBox(
offset: offset,
minExtent: minExtent,
resizable: resizable,
);
}
@override
void updateRenderObject(
BuildContext context, RenderResizableSheetChildBox renderObject) {
// Order dependency: The offset setter reads the axis direction.
renderObject
..offset = offset
..minExtent = minExtent
..resizable = resizable;
}
}
class RenderResizableSheetChildBox extends RenderShiftedBox {
RenderResizableSheetChildBox({
required ViewportOffset offset,
required double minExtent,
RenderBox? child,
bool resizable = true,
}) : _offset = offset,
_minExtent = minExtent,
_resizable = resizable,
super(child);
ViewportOffset get offset => _offset;
ViewportOffset _offset;
set offset(ViewportOffset value) {
if (value == _offset) return;
if (attached) _offset.removeListener(_hasScrolled);
_offset = value;
if (attached) _offset.addListener(_hasScrolled);
if (!resizable) return;
markNeedsLayout();
}
bool get resizable => _resizable;
bool _resizable;
set resizable(bool value) {
if (value == _resizable) return;
_resizable = value;
markNeedsLayout();
}
double get minExtent => _minExtent;
double _minExtent;
set minExtent(double value) {
if (value == _minExtent) return;
_minExtent = value;
if (!resizable) return;
markNeedsLayout();
}
void _hasScrolled() {
if (!resizable) return;
markNeedsLayout();
markNeedsSemanticsUpdate();
}
@override
void attach(PipelineOwner owner) {
super.attach(owner);
_offset.addListener(_hasScrolled);
}
@override
void detach() {
_offset.removeListener(_hasScrolled);
super.detach();
}
@override
void performLayout() {
final BoxParentData childParentData = child!.parentData! as BoxParentData;
// If not resizable we send constraints to child and
// parent size is the same as child
if (!resizable) {
child!.layout(
constraints,
parentUsesSize: true,
);
size = child!.size;
childParentData.offset = Offset.zero;
return;
}
// The height of the child will be the maximun between the offset pixels
// and the minExtent
final double extent = max(_offset.pixels, minExtent);
child!.layout(
BoxConstraints(
maxHeight: extent,
minHeight: extent,
minWidth: constraints.minWidth,
maxWidth: constraints.maxWidth,
),
parentUsesSize: true,
);
if (!constraints.hasTightHeight) {
size = Size(
child!.size.width, constraints.constrainHeight(child!.size.height));
childParentData.offset = Offset.zero;
} else {
size = constraints.biggest;
childParentData.offset = Offset.zero;
}
}
}