flutterquickactionandroid-appshortcut

Flutter Quick Actions change selected Bottom Navigation Bar item


I'm trying to implement home screen quick actions / app shortcuts in my Flutter app. What I'm trying to achieve is when the user launches my app via a quick action, the app changes the selected tab inside the bottom navigation bar. Any help is appreciated.

main.dart:

runApp(
    MaterialApp(
      theme: Themes.appLightTheme,
      darkTheme: Themes.appDarkTheme,
      home: QuickActionsController(
        child: HomeFrame(currentIndex: 0),
      ),

My QuickActionsController class:

import 'package:binfinder/screens/HomeFrame.dart';
import 'package:flutter/material.dart';
import 'package:quick_actions/quick_actions.dart';

class QuickActionsController extends StatefulWidget {
  final HomeFrame child;

  QuickActionsController({Key key, this.child}) : super(key: key);

  @override
  _QuickActionsControllerState createState() => _QuickActionsControllerState();
}

class _QuickActionsControllerState extends State<QuickActionsController> {
  final QuickActions quickActions = QuickActions();
  int _currentIndex = 0;

  @override
  void initState() {
    super.initState();
    _handleQuickActions();
    _setupQuickActions();
  }

  void _setupQuickActions() {
    quickActions.setShortcutItems(<ShortcutItem>[
      ShortcutItem(
        type: 'action_map',
        localizedTitle: 'Map',
      ),
    ]);
  }

  void _handleQuickActions() {
    quickActions.initialize((shortcutType) {
      if (shortcutType == 'action_map') {
        setState(() {
          _currentIndex = 1;
        });
      } else {
        setState(() {
          _currentIndex = 0;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    widget.child.currentIndex = _currentIndex;
    return widget.child;
  }
}


Solution

  • In the demo below, direct click app will enter First Page and In Quick Action choose Main view will enter Second Page

    _handleQuickActions need to use

    Navigator.pushReplacement(
            context,
            MaterialPageRoute(
                builder: (context) => BottomNavigationBarController(
                      initialIndex: 1,
                    )));
    

    and use initial index to control page index

    class BottomNavigationBarController extends StatefulWidget {
      final int initialIndex;
    
      BottomNavigationBarController({
        this.initialIndex,
        Key key,
      }) : super(key: key);
    
      @override
      _BottomNavigationBarControllerState createState() =>
          _BottomNavigationBarControllerState();
    }
    

    full code

    import 'package:flutter/material.dart';
    import 'package:quick_actions/quick_actions.dart';
    import 'dart:io';
    
    class QuickActionsManager extends StatefulWidget {
      final Widget child;
      QuickActionsManager({Key key, this.child}) : super(key: key);
    
      _QuickActionsManagerState createState() => _QuickActionsManagerState();
    }
    
    class _QuickActionsManagerState extends State<QuickActionsManager> {
      final QuickActions quickActions = QuickActions();
    
      @override
      void initState() {
        super.initState();
        _setupQuickActions();
        _handleQuickActions();
      }
    
      @override
      Widget build(BuildContext context) {
        return widget.child;
      }
    
      void _setupQuickActions() {
        quickActions.setShortcutItems(<ShortcutItem>[
          ShortcutItem(
              type: 'action_main',
              localizedTitle: 'Main view',
              icon: Platform.isAndroid ? 'quick_box' : 'QuickBox'),
          ShortcutItem(
              type: 'action_help',
              localizedTitle: 'Help',
              icon: Platform.isAndroid ? 'quick_heart' : 'QuickHeart')
        ]);
      }
    
      void _handleQuickActions() {
        quickActions.initialize((shortcutType) {
          if (shortcutType == 'action_main') {
            Navigator.pushReplacement(
                context,
                MaterialPageRoute(
                    builder: (context) => BottomNavigationBarController(
                          initialIndex: 1,
                        )));
          } else if (shortcutType == 'action_help') {
            print('Show the help dialog!');
          }
        });
      }
    }
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'QuickActions Demo',
            home: QuickActionsManager(child: BottomNavigationBarController(initialIndex: 0,)));
      }
    }
    
    class Home extends StatelessWidget {
      const Home({Key key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(body: Center(child: Text('Home')));
      }
    }
    
    class Login extends StatelessWidget {
      const Login({Key key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(body: Center(child: Text('Login')));
      }
    }
    
    class BottomNavigationBarController extends StatefulWidget {
      final int initialIndex;
    
      BottomNavigationBarController({
        this.initialIndex,
        Key key,
      }) : super(key: key);
    
      @override
      _BottomNavigationBarControllerState createState() =>
          _BottomNavigationBarControllerState();
    }
    
    class _BottomNavigationBarControllerState
        extends State<BottomNavigationBarController> {
      final List<Widget> pages = [
        FirstPage(
          key: PageStorageKey('Page1'),
        ),
        SecondPage(
          key: PageStorageKey('Page2'),
        ),
      ];
    
      final PageStorageBucket bucket = PageStorageBucket();
    
      int _selectedIndex = 0;
    
      Widget _bottomNavigationBar(int selectedIndex) => BottomNavigationBar(
            onTap: (int index) => setState(() => _selectedIndex = index),
            currentIndex: selectedIndex,
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                  icon: Icon(Icons.add), title: Text('First Page')),
              BottomNavigationBarItem(
                  icon: Icon(Icons.list), title: Text('Second Page')),
            ],
          );
    
      @override
      void initState() {
        _selectedIndex = widget.initialIndex;
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          bottomNavigationBar: _bottomNavigationBar(_selectedIndex),
          body: PageStorage(
            child: pages[_selectedIndex],
            bucket: bucket,
          ),
        );
      }
    }
    
    class FirstPage extends StatelessWidget {
      const FirstPage({Key key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("First Screen"),
          ),
          body: ListView.builder(itemBuilder: (context, index) {
            return ListTile(
              title: Text('Lorem Ipsum'),
              subtitle: Text('$index'),
            );
          }),
        );
      }
    }
    
    class SecondPage extends StatelessWidget {
      const SecondPage({Key key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Second Screen"),
          ),
          body: ListView.builder(itemBuilder: (context, index) {
            return ListTile(
              title: Text('Lorem Ipsum'),
              subtitle: Text('$index'),
            );
          }),
        );
      }
    }
    

    demo, emulator is a little slow when enter Second Page

    enter image description here