-
Notifications
You must be signed in to change notification settings - Fork 53
/
modal.dart
129 lines (116 loc) · 3.17 KB
/
modal.dart
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
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool showModal = false;
@override
Widget build(BuildContext context) {
return Portal(
child: MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Discovery example')),
body: Center(
child: Modal(
visible: showModal,
modal: const Dialog(
child: Text('Hello world'),
),
onClose: () => setState(() => showModal = false),
child: ElevatedButton(
onPressed: () => setState(() => showModal = true),
child: const Text('Show modal'),
),
),
),
),
),
);
}
}
class Modal extends StatelessWidget {
const Modal({
Key? key,
required this.visible,
required this.onClose,
required this.modal,
required this.child,
}) : super(key: key);
final Widget child;
final Widget modal;
final bool visible;
final VoidCallback onClose;
@override
Widget build(BuildContext context) {
return Barrier(
visible: visible,
onClose: onClose,
child: PortalTarget(
visible: visible,
closeDuration: kThemeAnimationDuration,
portalFollower: TweenAnimationBuilder<double>(
duration: kThemeAnimationDuration,
curve: Curves.easeOut,
tween: Tween(begin: 0, end: visible ? 1 : 0),
builder: (context, progress, child) {
return Transform(
transform: Matrix4.translationValues(0, (1 - progress) * 50, 0),
child: Opacity(
opacity: progress,
child: child,
),
);
},
child: Center(child: modal),
),
child: child,
),
);
}
}
class Barrier extends StatelessWidget {
const Barrier({
Key? key,
required this.onClose,
required this.visible,
required this.child,
}) : super(key: key);
final Widget child;
final VoidCallback onClose;
final bool visible;
@override
Widget build(BuildContext context) {
return PortalTarget(
visible: visible,
closeDuration: kThemeAnimationDuration,
portalFollower: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onClose,
child: TweenAnimationBuilder<Color>(
duration: kThemeAnimationDuration,
tween: ColorTween(
begin: Colors.transparent,
end: visible ? Colors.black54 : Colors.transparent,
),
builder: (context, color, child) {
return ColoredBox(color: color);
},
),
),
child: child,
);
}
}
/// Non-nullable version of ColorTween.
class ColorTween extends Tween<Color> {
ColorTween({required Color begin, required Color end})
: super(begin: begin, end: end);
@override
Color lerp(double t) => Color.lerp(begin, end, t)!;
}