如何同时使用Navigator.push和Navigator.push

时间:2020-11-03 21:25:03

标签: flutter navigator named-routing

我已向flutter应用程序添加了一些路线,以便在按下特定链接时将打开特定页面

这是主页的源代码

  import 'dart:convert';

import 'package:admob_flutter/admob_flutter.dart';
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:catcher/catcher.dart';
import 'package:dynamic_theme/dynamic_theme.dart';
import 'package:firebase_admob/firebase_admob.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:videos/c.dart';
import 'package:flutter/foundation.dart';
import 'package:videos/post.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;

import 'database/database.dart';
import 'database/database/mobile.dart' as mobile;
import 'src/app_route.dart';

void main() async{
  WidgetsFlutterBinding.ensureInitialized();
  FirebaseAdMob.instance.initialize(appId: APP_ID);
  Admob.initialize(APP_ID);
  await AndroidAlarmManager.initialize();

  CatcherOptions debugOptions =CatcherOptions(DialogReportMode(), [kIsWeb?ConsoleHandler(): EmailManualHandler(["ahmad.rajab@windowslive.com"])]);
  CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [
    kIsWeb?ToastHandler():EmailManualHandler(["ahmad.rajab@windowslive.com"])
  ]);
  Catcher(MyApp(), debugConfig: debugOptions, releaseConfig: releaseOptions);
}

class MyApp extends StatefulWidget{
  @override
  State<StatefulWidget> createState()=>MyAppState();
}

class MyAppState extends State<MyApp> {

  static Future configureDatabase()async{
    /*database = await openDatabase(DATABASE_NAME, version: DATABASE_VERSION,
    onCreate: (Database db, int version) async {
      await db.execute('create table $WATCHED_VIDEOS ($VIDEO_ID text,$REACHED_SECOND integer default 0,$NOTE text)');
      await db.execute('create table $TABLE_FAVORITE_VIDEOS ($VIDEO_TITLE text,$VIDEO_ID text,$VIDEO_DESCRIPTION text,$VIDEO_THUMBURL text)');
      await db.execute('create table $CHANNELS ($ID integer ,$NAME text,$LINK text, $PICTURE_LINK text,$VIEWED integer default 0,$GET_NOTIFICATIONS integer default 1,$LAST_VIDEO_TITLE text)');
     },
     onUpgrade: (db, oldVersion, newVersion)async {
       var tableColumns= await db.query('PRAGMA table_info($WATCHED_VIDEOS)');
       bool noteColumnExists=false;
       for(int c=0;c<tableColumns.length;c++){
         if(tableColumns[c]['name'].toString()==NOTE)noteColumnExists=true;
       }
       if(!noteColumnExists) await db.execute('alter table $WATCHED_VIDEOS add $NOTE text');
     },);
    */
  }

  AppRouterDelegate _routerDelegate = AppRouterDelegate();
  AppRouteInformationParser _routeInformationParser =
      AppRouteInformationParser();

  @override
  void initState() {
    super.initState();
    initialiseNotification();
    initialiseTimeZone();
    showDailyReminderNotification();
    configureDailyNewVideosFitch();
  }

  void configureDailyNewVideosFitch()async{
      await AndroidAlarmManager.periodic(const Duration(days: 1),DAILY_NEW_VIDEOS_FETCH_ALARAM_ID , ()async{
        Database d=RepositoryProvider.of<Database>(context);
        List<Channel>subscribedChannels=await (d.select($ChannelsTable(d))..where((tbl) => tbl.getNotifications.equals(1))).get();
        String channelsIds='';
        for(int i=0;i<subscribedChannels.length;i++)channelsIds+=subscribedChannels[i].link+"/";
        Map<String,String> map=Map();
        map['channels']=channelsIds;
        Post p=Post(context,'getVideosFromTime.php',map);
        await p.fetchPost();
        if(p.connectionSucceed){
          dynamic resultJson=json.decode(p.result);
          if(resultJson['result']=='success'){
            for(int i=0;i<resultJson['data'].length;i++){
              dynamic videoJson=resultJson['data'][i];
              await flutterLocalNotificationsPlugin.show(videoJson['id'], videoJson['channelName'], videoJson['title'],
               NotificationDetails(
                 android: AndroidNotificationDetails(
                   APP_NAME,
                   APP_NAME, NEW_VIDEO_AVAILABLE,
                   icon: '@mipmap/ic_launcher',
                   ticker: videoJson['title']
               ),
              ),
              payload:'/watch?v='+videoJson['videoId']
             );
            }
          }
        }
      },rescheduleOnReboot: true);

  }

  FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

  void showDailyReminderNotification()async{
    const AndroidNotificationDetails androidPlatformChannelSpecifics =
        AndroidNotificationDetails(APP_NAME,
            APP_NAME, 'dailyReminder'+APP_NAME,
            icon: '@mipmap/ic_launcher',
            ticker: TIME_TO_LEARN);
    const NotificationDetails platformChannelSpecifics =
        NotificationDetails(android: androidPlatformChannelSpecifics);
    await flutterLocalNotificationsPlugin.periodicallyShow(DAILY_REMINDER_NOTIFICATION_ID, TIME_TO_LEARN,
        TIME_TO_LEARN_DESCRIPTION, RepeatInterval.daily, platformChannelSpecifics,
        androidAllowWhileIdle: false);
  }

  void initialiseTimeZone()async{
    tz.initializeTimeZones();
    tz.setLocalLocation(tz.getLocation(await FlutterNativeTimezone.getLocalTimezone()));
  }

  void initialiseNotification()async{
   flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();
  // initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
  const AndroidInitializationSettings initializationSettingsAndroid =
      AndroidInitializationSettings('@mipmap/ic_launcher');
  final IOSInitializationSettings initializationSettingsIOS =
      IOSInitializationSettings(
          /*onDidReceiveLocalNotification: onDidReceiveLocalNotification*/);
  final MacOSInitializationSettings initializationSettingsMacOS =
      MacOSInitializationSettings();
  final InitializationSettings initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
      macOS: initializationSettingsMacOS);
  await flutterLocalNotificationsPlugin.initialize(initializationSettings,
      onSelectNotification: selectNotification);
  await flutterLocalNotificationsPlugin.cancel(DAILY_REMINDER_NOTIFICATION_ID);
}

Future selectNotification(String payload) async {
    if(payload!=null)Navigator.pushNamed(context, payload);
}

  @override
  Widget build(BuildContext context) {
    return DynamicTheme(
          defaultBrightness: Brightness.light,
          data: (brightness) => ThemeData(
            primarySwatch: PRIMARY_COLOR,
            brightness: brightness
          ),
          themedWidgetBuilder: (context, data) {
     return RepositoryProvider<Database>(
      create:(context)=>mobile.constructDb() ,
      child: BlocProvider(
        create: (context){
          //final db = RepositoryProvider.of<Database>(context);
          //return AppBloc(db);
        },
        child: MaterialApp.router(
              //title: 'Books App',
              theme: data,
              routerDelegate: _routerDelegate,
              routeInformationParser: _routeInformationParser,
        )
      )
     );
    }
  );
}
}

MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
  // ignore: deprecated_member_use
  gender: MobileAdGender.unknown,
  childDirected: true
);

class AdmobAdd extends StatelessWidget{
    @override
  Widget build(BuildContext context) {
    return !PRO?AdmobBanner(
              adUnitId: kReleaseMode?BANNER_AD_UNIT_ID:BannerAd.testAdUnitId,
              adSize: AdmobBannerSize.BANNER,
              ):Container();
  }
  }

InterstitialAd myInterstitial = InterstitialAd(
  adUnitId: InterstitialAd.testAdUnitId,
  targetingInfo: targetingInfo,
);

这是路由配置文件的源代码

   import 'package:catcher/catcher.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:videos/home.dart';
import 'package:videos/video.dart';

class AppRouteInformationParser extends RouteInformationParser<AppRoutePath> {
  @override
  Future<AppRoutePath> parseRouteInformation(
      RouteInformation routeInformation) async {
    final uri = Uri.parse(routeInformation.location);
    // Handle '/'
    if (uri.pathSegments.length == 0) {
      return AppRoutePath.home();
    }

    // Handle '/watch?v=fsdfsdfsd
    if (uri.pathSegments.length == 1) {
      if (!uri.pathSegments[0].startsWith('/watch?')) return AppRoutePath.unknown();
      if(uri.pathSegments[0].startsWith('/watch?v=')){
        var videoId=uri.queryParameters['v'];
        return AppRoutePath.video(videoId);
        /*var remaining = uri.pathSegments[1];
        var id = int.tryParse(remaining);
        if (id == null) return AppRoutePath.unknown();
        return AppRoutePath.details(id);*/
      }
    }

    // Handle unknown routes
    return AppRoutePath.unknown();
  }

  @override
  RouteInformation restoreRouteInformation(AppRoutePath path) {
    if (path.isUnknown) {
      return RouteInformation(location: '/404');
    }
    if (path.isHomePage) {
      return RouteInformation(location: '/');
    }
    if(path.isVideoPage){
      return RouteInformation(location: '/watch?v=${path.id}');
    }
    if (path.isDetailsPage) {
      return RouteInformation(location: '/book/${path.id}');
    }
    return null;
  }
}

class AppRouterDelegate extends RouterDelegate<AppRoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoutePath> {
  final GlobalKey<NavigatorState> navigatorKey;

  //Book _selectedBook;
  bool show404 = false;
  String videoId;
  /*List<Book> books = [
    Book('Stranger in a Strange Land', 'Robert A. Heinlein'),
    Book('Foundation', 'Isaac Asimov'),
    Book('Fahrenheit 451', 'Ray Bradbury'),
  ];*/

  AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();

  AppRoutePath get currentConfiguration {
    if (show404) {
      return AppRoutePath.unknown();
    }
    if(videoId!=null) return AppRoutePath.video(videoId);
    /*return _selectedBook == null
        ? AppRoutePath.home()
        : AppRoutePath.details(books.indexOf(_selectedBook));*/
    return AppRoutePath.home();
  }

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: Catcher.navigatorKey,
      pages: [
        MaterialPage(
          key: ValueKey('Home'),
          child: MyHomePage()
        ),
        if (show404)
          MaterialPage(key: ValueKey('Unknown'), child: UnknownScreen())
        else if(videoId!=null) VideoPageRoute(videoId: videoId)
        /*else if (_selectedBook != null)
          BookDetailsPage(book: _selectedBook)*/
      ],
      onPopPage: (route, result) {
        if (!route.didPop(result)) {
          return false;
        }

        // Update the list of pages by setting _selectedBook to null
        //_selectedBook = null;
        videoId=null;
        show404 = false;
        notifyListeners();

        return true;
      },
    );
  }

  @override
  Future<void> setNewRoutePath(AppRoutePath path) async {
    if (path.isUnknown) {
      //_selectedBook = null;
      videoId=null;
      show404 = true;
      return;
    }

    /*if (path.isDetailsPage) {
      if (path.id < 0 || path.id > books.length - 1) {
        show404 = true;
        return;
      }

      _selectedBook = books[path.id];
    } else {
      _selectedBook = null;
    }*/

    show404 = false;
  }

  void videoNotFound(){
    videoId=null;
    show404=true;
    notifyListeners();
  }

  /*void _handleBookTapped(Book book) {
    _selectedBook = book;
    notifyListeners();
  }*/
}

class AppRoutePath {
  final String id;
  final bool isUnknown;

  AppRoutePath.home()
      : id = null,
        isUnknown = false;

  AppRoutePath.details(this.id) : isUnknown = false;

  AppRoutePath.video(this.id): isUnknown=false;

  AppRoutePath.unknown()
      : id = null,
        isUnknown = true;

  bool get isHomePage => id == null;

  bool get isDetailsPage => id != null;

  bool get isVideoPage => id!=null;
}

/*class BooksListScreen extends StatelessWidget {
  final List<Book> books;
  final ValueChanged<Book> onTapped;

  BooksListScreen({
    @required this.books,
    @required this.onTapped,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: ListView(
        children: [
          for (var book in books)
            ListTile(
              title: Text(book.title),
              subtitle: Text(book.author),
              onTap: () => onTapped(book),
            )
        ],
      ),
    );
  }
}
*/
/*class BookDetailsScreen extends StatelessWidget {
  final Book book;

  BookDetailsScreen({
    @required this.book,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            if (book != null) ...[
              Text(book.title, style: Theme.of(context).textTheme.headline6),
              Text(book.author, style: Theme.of(context).textTheme.subtitle1),
            ],
          ],
        ),
      ),
    );
  }
}
*/
class UnknownScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text('404!'),
      ),
    );
  }
}

问题是我有几个没有特定URL的屏幕,我不想为它们提供路由,我只想使用Navigator.push()

这很好,但是当按下“后退”按钮或我使用Navigator.pop()时,应用程序将完全关闭,而不是导航回上一页

如何仅将Navigator.pushNamed用于命名路由,如何将Navigator.push用于其他页面,而不会导致问题发生

预先感谢

0 个答案:

没有答案