| // 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. |
| |
| /// Flutter code sample for [Overlay]. |
| |
| import 'package:flutter/material.dart'; |
| |
| 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); |
| |
| 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: (BuildContext context) { |
| switch (currentPageIndex) { |
| case 0: |
| return Column( |
| children: const <Widget>[ |
| Text( |
| 'Explore page', |
| style: TextStyle( |
| color: Colors.red, |
| ), |
| ), |
| Icon( |
| Icons.arrow_downward, |
| color: Colors.red |
| ), |
| ], |
| ); |
| case 1: |
| return Column( |
| children: const <Widget>[ |
| Text( |
| 'Commute page', |
| style: TextStyle( |
| color: Colors.green, |
| ), |
| ), |
| Icon( |
| Icons.arrow_downward, |
| color: Colors.green |
| ), |
| ], |
| ); |
| case 2: |
| return Column( |
| children: const <Widget>[ |
| Text( |
| 'Saved page', |
| style: TextStyle( |
| color: Colors.orange, |
| ), |
| ), |
| Icon( |
| Icons.arrow_downward, |
| color: Colors.orange |
| ), |
| ], |
| ); |
| default: |
| return const Text('No page selected.'); |
| } |
| }), |
| 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 = 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: Column( |
| mainAxisAlignment: MainAxisAlignment.center, |
| children: <Widget>[ |
| Text( |
| 'Use Overlay to highlight a NavigationBar destination', |
| style: Theme.of(context).textTheme.bodyMedium, |
| ), |
| const SizedBox(height: 20.0), |
| Row( |
| mainAxisAlignment: MainAxisAlignment.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'), |
| ), |
| const SizedBox(width: 20.0), |
| // 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'), |
| ), |
| const SizedBox(width: 20.0), |
| // 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'), |
| ), |
| ], |
| ), |
| const SizedBox(height: 10.0), |
| ElevatedButton( |
| onPressed: () { |
| removeHighlightOverlay(); |
| }, |
| child: const Text('Remove Overlay'), |
| ), |
| ], |
| ), |
| ); |
| } |
| } |