Learning how to use OverlayPortal
and CompositedTransformTarget
to build a custom dropdown in Flutter without external packages!
This is part of an article I wrote in DEV.to, go check it out! :)
import 'package:flutter/material.dart'; | |
void main() => runApp(const App()); | |
final class App extends StatelessWidget { | |
const App({super.key}); | |
@override | |
Widget build(BuildContext context) => MaterialApp( | |
theme: ThemeData.light(), | |
darkTheme: ThemeData.dark(), | |
home: const HomeScreen(), | |
); | |
} | |
final class HomeScreen extends StatelessWidget { | |
const HomeScreen({super.key}); | |
static final _controller = OverlayPortalController(); | |
static final _link = LayerLink(); | |
@override | |
Widget build(BuildContext context) => Scaffold( | |
appBar: AppBar(title: const Text('Custom dropdown'),), | |
body: Center( | |
child: SizedBox( | |
height: 64, | |
width: 200, | |
child: LayoutBuilder( | |
builder: (context, limits) => OverlayPortal( | |
controller: _controller, | |
overlayChildBuilder: (context) => UnconstrainedBox( | |
child: CompositedTransformFollower( | |
link: _link, | |
offset: const Offset(0, 12), | |
targetAnchor: Alignment.bottomLeft, | |
child: Container( | |
width: limits.maxWidth, | |
height: limits.maxHeight, | |
decoration: BoxDecoration( | |
color: Theme.of(context).colorScheme.surfaceContainer, | |
borderRadius: BorderRadius.circular(16), | |
), | |
alignment: Alignment.center, | |
child: const Text('Dropdown'), | |
), | |
), | |
), | |
child: CompositedTransformTarget( | |
link: _link, | |
child: ElevatedButton( | |
onPressed: _controller.toggle, | |
child: const Text('Toggle dropdown'), | |
), | |
), | |
), | |
), | |
), | |
), | |
); | |
} |