I'm trying to build a custom pop-up in Flutter/Dart using the following features:
Please refer to the attached images for an example of this implementation in IOS. I desire to achieve the same thing using Flutter/Dart.
The popups included in Flutter framework are rudimentary. Any ideas on how this is done?
I'm not a flutter pro at all but just out of curiosity I tried to implement as much as I can of your targets in my free time.
You can show a popup without blocking the scroll. And you can push and pop the content of popup.
I'm not claiming that it's an efficient or a healthy way to do things. It's not complete but I think you can go on and build on it. If you decide to use it I think it would be best to;
class MyScaffold extends StatefulWidget {
const MyScaffold({Key? key}) : super(key: key);
@override
State<MyScaffold> createState() => _MyScaffoldState();
}
class _MyScaffoldState extends State<MyScaffold> {
CustomPopupController customPopupController = CustomPopupController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("NonBlocking PopUp")),
body: Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: PopupBase(
child: RichTextContent(),
)),
),
),
],
),
);
}
}
class PopupBase extends StatefulWidget {
const PopupBase({Key? key, required this.child}) : super(key: key);
final Widget child;
@override
State<PopupBase> createState() => _PopupBaseState();
static _PopupBaseState of(BuildContext context) =>
context.findAncestorStateOfType<_PopupBaseState>()!;
}
class _PopupBaseState extends State<PopupBase> {
List<Widget> popupStack = List.empty(growable: true);
@override
void initState() {
super.initState();
popupStack.add(widget.child);
}
void showPopup(CustomPopup popup, Offset position) {
setState(() {
popupStack.add(Positioned(
child: popup,
left: position.dx,
top: position.dy,
));
});
}
void removePopup(CustomPopup popup) {
print("popupbase remove");
setState(() {
popupStack.removeLast();
});
print(popupStack.length);
}
@override
Widget build(BuildContext context) {
return Stack(
children: popupStack,
);
}
}
class CustomPopupController {
late bool Function(Widget) push;
late Widget Function()? pop;
}
class CustomPopup extends StatefulWidget {
CustomPopup({Key? key, required this.content, required this.controller})
: super(key: key);
Widget content;
final CustomPopupController controller;
@override
State<CustomPopup> createState() => _CustomPopupState();
static _CustomPopupState of(BuildContext context) =>
context.findAncestorStateOfType<_CustomPopupState>()!;
}
class _CustomPopupState extends State<CustomPopup> {
@override
void initState() {
super.initState();
widget.controller.push = push;
widget.controller.pop = pop;
}
final List<Widget> _contentStack = List.empty(growable: true);
bool push(Widget widgetToPush) {
_contentStack.add(widget.content);
setState(() {
widget.content = widgetToPush;
});
return false;
}
Widget pop() {
if (_contentStack.isNotEmpty) {
Widget temp = widget.content;
setState(() {
widget.content = _contentStack.last;
_contentStack.removeLast();
});
return temp;
} else {
PopupBase.of(context).removePopup(this.widget);
return widget.content;
}
}
@override
Widget build(BuildContext context) {
return Card(
child: SizedBox(
height: 300,
width: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
color: Colors.red,
height: 25,
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
(_contentStack.isNotEmpty)
? Padding(
padding: EdgeInsets.only(left: 10),
child: InkWell(
onTap: () {
pop();
},
child: Icon(Icons.arrow_back_ios)),
)
: Container(),
Expanded(child: Container()),
Padding(
padding: EdgeInsets.only(left: 10),
child: InkWell(
onTap: () {
pop();
},
child: Icon(Icons.close)),
)
],
),
),
Expanded(
child: SingleChildScrollView(
child: widget.content,
))
],
)),
);
}
}
class RichTextContent extends StatelessWidget {
RichTextContent({Key? key}) : super(key: key);
TextStyle text = TextStyle(color: Colors.black);
TextStyle clickable = TextStyle(color: Colors.blue);
@override
Widget build(BuildContext context) {
CustomPopupController controller = CustomPopupController();
return RichText(
text: TextSpan(children: [
TextSpan(style: text, text: """Lorem ipsum dolor sit """),
TextSpan(
text: 'amet',
style: clickable,
recognizer: TapGestureRecognizer()
..onTapUp = (TapUpDetails details) {
PopupBase.of(context).showPopup(
CustomPopup(content: Text("Popup"), controller: controller),
details.localPosition);
}),
TextSpan(
style: text,
text:
""", consectetur adipiscing elit. Nulla bibendum at massa et euismod. Praesent ex ipsum, ultrices ut rhoncus et, efficitur vehicula mi. Duis sollicitudin dolor sed tristique molestie. Ut eu elit velit. Cras et lorem quis risus mattis porta vitae ac velit. Nunc laoreet malesuada lectus at laoreet. Etiam ut tristique nulla. Pellentesque eros est, pretium sit amet convallis ut, convallis eu justo. Nulla suscipit blandit massa. Vestibulum vitae magna eu urna faucibus hendrerit. Etiam eros nibh, venenatis ac ullamcorper vitae, venenatis ac neque. Aenean vitae erat massa. Aliquam vulputate facilisis volutpat. Sed tincidunt dolor a enim dictum, eget tristique nisi laoreet. Quisque suscipit, odio et mattis mattis, lectus justo lacinia enim, nec finibus mi ante gravida sem.
Nunc ac nunc nec sapien porttitor volutpat. In et accumsan est. Duis non dui porta, pharetra dolor consequat, bibendum lorem. Quisque suscipit sit amet mi ac placerat. Integer cursus, est nec aliquet consequat, felis erat sodales sem, eget maximus ante libero in nibh. Cras et orci magna. Suspendisse viverra nibh eget nulla mattis laoreet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi tortor diam, pulvinar quis erat a, posuere vehicula ante. Sed aliquet et magna nec finibus. Morbi in dapibus risus. Nullam ac imperdiet enim.
Nam enim mauris, volutpat et metus ut, euismod porttitor odio. Duis at orci hendrerit, posuere tortor sed, convallis nibh. Nullam lobortis est eget magna finibus porttitor. Nulla facilisi. Donec bibendum ac lorem eget consectetur. Phasellus at lacinia augue. Integer a mi quam. Morbi malesuada maximus diam. In orci nisi, mollis sed urna eget, fermentum efficitur libero. Cras auctor est sit amet ex aliquet, eu rutrum turpis gravida. Donec mattis, erat eget ultricies accumsan, odio urna egestas lectus, at mattis lorem sem scelerisque dolor. Curabitur aliquet venenatis bibendum.
"""),
]));
}
}