Skip to content

Commit 45705d9

Browse files
author
Victor Ohashi
committed
fix: Improve popover render
1 parent 1463db6 commit 45705d9

File tree

2 files changed

+119
-163
lines changed

2 files changed

+119
-163
lines changed

lib/src/popover.dart

+35-65
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ import 'utils/popover_utils.dart';
6363
///
6464
/// The `onPop` called to veto attempts by the user to dismiss the popover.
6565
///
66-
/// Pass `mounted` property from parent widget to the `isParentAlive`
67-
/// function to prevent red screen of death.
68-
/// `isParentAlive : () => mounted`
69-
///
7066
/// The `constraints` is popover's constraints.
7167
///
7268
/// The `routeSettings` is data that might be useful in constructing a [Route].
@@ -96,7 +92,6 @@ Future<T?> showPopover<T extends Object?>({
9692
double? width,
9793
double? height,
9894
VoidCallback? onPop,
99-
bool Function()? isParentAlive,
10095
BoxConstraints? constraints,
10196
RouteSettings? routeSettings,
10297
String? barrierLabel,
@@ -110,73 +105,48 @@ Future<T?> showPopover<T extends Object?>({
110105

111106
return Navigator.of(context, rootNavigator: true).push<T>(
112107
RawDialogRoute<T>(
113-
pageBuilder: (_, __, ___) {
114-
return Builder(builder: (_) => const SizedBox.shrink());
108+
pageBuilder: (_, animation, __) {
109+
return WillPopScope(
110+
onWillPop: () {
111+
onPop?.call();
112+
return Future.value(true);
113+
},
114+
child: PopoverItem(
115+
transition: transition,
116+
child: Builder(builder: bodyBuilder),
117+
context: context,
118+
backgroundColor: backgroundColor,
119+
direction: direction,
120+
radius: radius,
121+
boxShadow: shadow,
122+
animation: animation,
123+
arrowWidth: arrowWidth,
124+
arrowHeight: arrowHeight,
125+
constraints: constraints,
126+
arrowDxOffset: arrowDxOffset,
127+
arrowDyOffset: arrowDyOffset,
128+
contentDyOffset: contentDyOffset,
129+
key: key,
130+
),
131+
);
132+
},
133+
transitionBuilder: (builderContext, animation, _, child) {
134+
return popoverTransitionBuilder == null
135+
? FadeTransition(
136+
opacity: CurvedAnimation(
137+
parent: animation,
138+
curve: Curves.easeOut,
139+
),
140+
child: child,
141+
)
142+
: popoverTransitionBuilder(animation, child);
115143
},
116144
barrierDismissible: barrierDismissible,
117145
barrierLabel: barrierLabel ??=
118146
MaterialLocalizations.of(context).modalBarrierDismissLabel,
119147
barrierColor: barrierColor,
120148
transitionDuration: transitionDuration,
121149
settings: routeSettings,
122-
transitionBuilder: (builderContext, animation, _, child) {
123-
return WillPopScope(
124-
onWillPop: () {
125-
if (onPop != null) {
126-
onPop();
127-
return Future.value(true);
128-
} else {
129-
return Future.value(true);
130-
}
131-
},
132-
child: popoverTransitionBuilder == null
133-
? FadeTransition(
134-
opacity: CurvedAnimation(
135-
parent: animation,
136-
curve: Curves.easeOut,
137-
),
138-
child: PopoverItem(
139-
transition: transition,
140-
child: bodyBuilder(builderContext),
141-
context: context,
142-
backgroundColor: backgroundColor,
143-
direction: direction,
144-
radius: radius,
145-
boxShadow: shadow,
146-
animation: animation,
147-
arrowWidth: arrowWidth,
148-
arrowHeight: arrowHeight,
149-
constraints: constraints,
150-
arrowDxOffset: arrowDxOffset,
151-
arrowDyOffset: arrowDyOffset,
152-
contentDyOffset: contentDyOffset,
153-
isParentAlive: isParentAlive,
154-
key: key,
155-
),
156-
)
157-
: popoverTransitionBuilder(
158-
animation,
159-
PopoverItem(
160-
transition: transition,
161-
child: bodyBuilder(builderContext),
162-
context: context,
163-
backgroundColor: backgroundColor,
164-
direction: direction,
165-
radius: radius,
166-
boxShadow: shadow,
167-
animation: animation,
168-
arrowWidth: arrowWidth,
169-
arrowHeight: arrowHeight,
170-
constraints: constraints,
171-
arrowDxOffset: arrowDxOffset,
172-
arrowDyOffset: arrowDyOffset,
173-
contentDyOffset: contentDyOffset,
174-
isParentAlive: isParentAlive,
175-
key: key,
176-
),
177-
),
178-
);
179-
},
180150
),
181151
);
182152
}

lib/src/popover_item.dart

+84-98
Original file line numberDiff line numberDiff line change
@@ -4,116 +4,55 @@ import '../popover.dart';
44
import 'popover_context.dart';
55
import 'popover_position_widget.dart';
66
import 'utils/build_context_extension.dart';
7-
import 'utils/utils.dart';
87

98
class PopoverItem extends StatefulWidget {
109
final Widget child;
1110
final Color? backgroundColor;
1211
final PopoverDirection? direction;
1312
final double? radius;
1413
final List<BoxShadow>? boxShadow;
15-
final Animation<double>? animation;
14+
final Animation<double> animation;
1615
final double? arrowWidth;
17-
final double? arrowHeight;
16+
final double arrowHeight;
1817
final BoxConstraints? constraints;
1918
final BuildContext context;
20-
final double? arrowDxOffset;
21-
final double? arrowDyOffset;
22-
final double? contentDyOffset;
23-
final bool Function()? isParentAlive;
19+
final double arrowDxOffset;
20+
final double arrowDyOffset;
21+
final double contentDyOffset;
2422
final PopoverTransition transition;
2523

2624
const PopoverItem({
2725
required this.child,
2826
required this.context,
2927
required this.transition,
28+
required this.animation,
29+
required this.arrowHeight,
3030
this.backgroundColor,
3131
this.direction,
3232
this.radius,
3333
this.boxShadow,
34-
this.animation,
3534
this.arrowWidth,
36-
this.arrowHeight,
3735
this.constraints,
38-
this.arrowDxOffset,
39-
this.arrowDyOffset,
40-
this.contentDyOffset,
41-
this.isParentAlive,
42-
Key? key,
43-
}) : super(key: key);
36+
this.arrowDxOffset = 0,
37+
this.arrowDyOffset = 0,
38+
this.contentDyOffset = 0,
39+
super.key,
40+
});
4441

4542
@override
4643
_PopoverItemState createState() => _PopoverItemState();
4744
}
4845

4946
class _PopoverItemState extends State<PopoverItem> {
50-
late BoxConstraints constraints;
51-
late Offset offset;
52-
late Rect bounds;
53-
late Rect attachRect;
54-
55-
@override
56-
Widget build(BuildContext context) {
57-
return LayoutBuilder(
58-
builder: (_, __) {
59-
_configure();
60-
return Stack(
61-
children: [
62-
PopoverPositionWidget(
63-
attachRect: attachRect,
64-
scale: widget.animation,
65-
constraints: constraints,
66-
direction: widget.direction,
67-
arrowHeight: widget.arrowHeight,
68-
child: PopoverContext(
69-
attachRect: attachRect,
70-
animation: widget.animation,
71-
radius: widget.radius,
72-
backgroundColor: widget.backgroundColor,
73-
boxShadow: widget.boxShadow,
74-
direction: widget.direction,
75-
arrowWidth: widget.arrowWidth,
76-
arrowHeight: widget.arrowHeight,
77-
transition: widget.transition,
78-
child: Material(
79-
type: MaterialType.transparency,
80-
child: widget.child,
81-
),
82-
),
83-
)
84-
],
85-
);
86-
},
87-
);
88-
}
89-
90-
void _configure() {
91-
final bool isParentAlive;
92-
93-
if (widget.isParentAlive != null) {
94-
isParentAlive = widget.isParentAlive!();
95-
} else {
96-
isParentAlive = true;
97-
}
98-
99-
if (!isParentAlive) {
100-
return;
101-
}
102-
103-
final box = widget.context.findRenderObject() as RenderBox;
104-
if (mounted && box.owner != null) {
105-
_configureConstraints();
106-
_configureRect();
107-
}
108-
}
47+
late Rect _attachRect;
48+
BoxConstraints? _constraints;
10949

11050
void _configureConstraints() {
111-
BoxConstraints _constraints;
51+
final size = MediaQuery.of(context).size;
52+
var constraints = BoxConstraints.loose(size);
53+
11254
if (widget.constraints != null) {
113-
_constraints = BoxConstraints(
114-
maxHeight: Utils().screenHeight / 2,
115-
maxWidth: Utils().screenHeight / 2,
116-
).copyWith(
55+
constraints = constraints.copyWith(
11756
minWidth: widget.constraints!.minWidth.isFinite
11857
? widget.constraints!.minWidth
11958
: null,
@@ -127,34 +66,81 @@ class _PopoverItemState extends State<PopoverItem> {
12766
? widget.constraints!.maxHeight
12867
: null,
12968
);
130-
} else {
131-
_constraints = BoxConstraints(
132-
maxHeight: Utils().screenHeight / 2,
133-
maxWidth: Utils().screenHeight / 2,
134-
);
13569
}
70+
13671
if (widget.direction == PopoverDirection.top ||
13772
widget.direction == PopoverDirection.bottom) {
138-
constraints = _constraints.copyWith(
139-
maxHeight: _constraints.maxHeight + widget.arrowHeight!,
140-
maxWidth: _constraints.maxWidth,
141-
);
73+
final maxHeight = constraints.maxHeight + widget.arrowHeight;
74+
constraints = constraints.copyWith(maxHeight: maxHeight);
14275
} else {
143-
constraints = _constraints.copyWith(
144-
maxHeight: _constraints.maxHeight + widget.arrowHeight!,
145-
maxWidth: _constraints.maxWidth + widget.arrowWidth!,
76+
constraints = constraints.copyWith(
77+
maxHeight: constraints.maxHeight + widget.arrowHeight,
78+
maxWidth: constraints.maxWidth + widget.arrowWidth!,
14679
);
14780
}
81+
82+
_constraints = constraints;
14883
}
14984

15085
void _configureRect() {
151-
offset = BuildContextExtension.getWidgetLocalToGlobal(widget.context);
152-
bounds = BuildContextExtension.getWidgetBounds(widget.context);
153-
attachRect = Rect.fromLTWH(
154-
offset.dx + (widget.arrowDxOffset ?? 0.0),
155-
offset.dy + (widget.arrowDyOffset ?? 0.0),
156-
bounds.width,
157-
bounds.height + (widget.contentDyOffset ?? 0.0),
86+
final offset = BuildContextExtension.getWidgetLocalToGlobal(widget.context);
87+
final bounds = BuildContextExtension.getWidgetBounds(widget.context);
88+
89+
if (offset != null && bounds != null) {
90+
_attachRect = Rect.fromLTWH(
91+
offset.dx + (widget.arrowDxOffset),
92+
offset.dy + (widget.arrowDyOffset),
93+
bounds.width,
94+
bounds.height + (widget.contentDyOffset),
95+
);
96+
}
97+
}
98+
99+
@override
100+
void initState() {
101+
_configureRect();
102+
super.initState();
103+
}
104+
105+
@override
106+
void didChangeDependencies() {
107+
_configureConstraints();
108+
WidgetsBinding.instance.addPostFrameCallback(
109+
(_) => setState(_configureRect),
110+
);
111+
112+
super.didChangeDependencies();
113+
}
114+
115+
@override
116+
Widget build(BuildContext context) {
117+
return Stack(
118+
children: [
119+
PopoverPositionWidget(
120+
attachRect: _attachRect,
121+
constraints: _constraints,
122+
direction: widget.direction,
123+
arrowHeight: widget.arrowHeight,
124+
child: AnimatedBuilder(
125+
animation: widget.animation,
126+
builder: (context, child) {
127+
return PopoverContext(
128+
attachRect: _attachRect,
129+
animation: widget.animation,
130+
radius: widget.radius,
131+
backgroundColor: widget.backgroundColor,
132+
boxShadow: widget.boxShadow,
133+
direction: widget.direction,
134+
arrowWidth: widget.arrowWidth,
135+
arrowHeight: widget.arrowHeight,
136+
transition: widget.transition,
137+
child: child,
138+
);
139+
},
140+
child: Material(child: widget.child),
141+
),
142+
)
143+
],
158144
);
159145
}
160146
}

0 commit comments

Comments
 (0)