| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/material.dart'; |
| |
| /// Flutter code sample for [Overlay]. |
| |
| void main() => runApp(const OverlayApp()); |
| |
| class OverlayApp extends StatelessWidget { |
| const OverlayApp({super.key}); |
| |
| @override |
| Widget build(BuildContext context) { |
| return const MaterialApp(home: OverlayExample()); |
| } |
| } |
| |
| class OverlayExample extends StatefulWidget { |
| const OverlayExample({super.key}); |
| |
| @override |
| State<OverlayExample> createState() => _OverlayExampleState(); |
| } |
| |
| class _OverlayExampleState extends State<OverlayExample> { |
| OverlayEntry? overlayEntry; |
| int currentPageIndex = 0; |
| |
| void createHighlightOverlay({ |
| required AlignmentDirectional alignment, |
| required Color borderColor, |
| }) { |
| // Remove the existing OverlayEntry. |
| removeHighlightOverlay(); |
| |
| assert(overlayEntry == null); |
| |
| Widget builder(BuildContext context) { |
| final (String label, Color? color) = switch (currentPageIndex) { |
| 0 => ('Explore page', Colors.red), |
| 1 => ('Commute page', Colors.green), |
| 2 => ('Saved page', Colors.orange), |
| _ => ('No page selected.', null), |
| }; |
| if (color == null) { |
| return Text(label); |
| } |
| return Column( |
| children: <Widget>[ |
| Text(label, style: TextStyle(color: color)), |
| Icon(Icons.arrow_downward, color: color), |
| ], |
| ); |
| } |
| |
| overlayEntry = OverlayEntry( |
| // Create a new OverlayEntry. |
| builder: (BuildContext context) { |
| // Align is used to position the highlight overlay |
| // relative to the NavigationBar destination. |
| return SafeArea( |
| child: Align( |
| alignment: alignment, |
| heightFactor: 1.0, |
| child: DefaultTextStyle( |
| style: const TextStyle( |
| color: Colors.blue, |
| fontWeight: FontWeight.bold, |
| fontSize: 14.0, |
| ), |
| child: Column( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[ |
| const Text('Tap here for'), |
| Builder(builder: builder), |
| SizedBox( |
| width: MediaQuery.of(context).size.width / 3, |
| height: 80.0, |
| child: Center( |
| child: Container( |
| decoration: BoxDecoration( |
| border: Border.all(color: borderColor, width: 4.0), |
| ), |
| ), |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| }, |
| ); |
| |
| // Add the OverlayEntry to the Overlay. |
| Overlay.of(context, debugRequiredFor: widget).insert(overlayEntry!); |
| } |
| |
| // Remove the OverlayEntry. |
| void removeHighlightOverlay() { |
| overlayEntry?.remove(); |
| overlayEntry?.dispose(); |
| overlayEntry = null; |
| } |
| |
| @override |
| void dispose() { |
| // Make sure to remove OverlayEntry when the widget is disposed. |
| removeHighlightOverlay(); |
| super.dispose(); |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return Scaffold( |
| appBar: AppBar(title: const Text('Overlay Sample')), |
| bottomNavigationBar: NavigationBar( |
| selectedIndex: currentPageIndex, |
| destinations: const <NavigationDestination>[ |
| NavigationDestination(icon: Icon(Icons.explore), label: 'Explore'), |
| NavigationDestination(icon: Icon(Icons.commute), label: 'Commute'), |
| NavigationDestination( |
| selectedIcon: Icon(Icons.bookmark), |
| icon: Icon(Icons.bookmark_border), |
| label: 'Saved', |
| ), |
| ], |
| ), |
| body: Center( |
| child: Padding( |
| padding: const EdgeInsets.all(8.0), |
| child: Column( |
| spacing: 10.0, |
| mainAxisAlignment: MainAxisAlignment.center, |
| children: <Widget>[ |
| Text( |
| 'Use Overlay to highlight a NavigationBar destination', |
| style: Theme.of(context).textTheme.bodyMedium, |
| ), |
| Wrap( |
| spacing: 10.0, |
| runSpacing: 10.0, |
| alignment: WrapAlignment.center, |
| runAlignment: WrapAlignment.center, |
| children: <Widget>[ |
| // This creates a highlight Overlay for |
| // the Explore item. |
| ElevatedButton( |
| onPressed: () { |
| setState(() { |
| currentPageIndex = 0; |
| }); |
| createHighlightOverlay( |
| alignment: AlignmentDirectional.bottomStart, |
| borderColor: Colors.red, |
| ); |
| }, |
| child: const Text('Explore'), |
| ), |
| // This creates a highlight Overlay for |
| // the Commute item. |
| ElevatedButton( |
| onPressed: () { |
| setState(() { |
| currentPageIndex = 1; |
| }); |
| createHighlightOverlay( |
| alignment: AlignmentDirectional.bottomCenter, |
| borderColor: Colors.green, |
| ); |
| }, |
| child: const Text('Commute'), |
| ), |
| // This creates a highlight Overlay for |
| // the Saved item. |
| ElevatedButton( |
| onPressed: () { |
| setState(() { |
| currentPageIndex = 2; |
| }); |
| createHighlightOverlay( |
| alignment: AlignmentDirectional.bottomEnd, |
| borderColor: Colors.orange, |
| ); |
| }, |
| child: const Text('Saved'), |
| ), |
| ], |
| ), |
| ElevatedButton( |
| onPressed: () { |
| removeHighlightOverlay(); |
| }, |
| child: const Text('Remove Overlay'), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| } |
| } |