BottomNavigationBar с шаблоном BLoC

Мне очень нравится шаблон BLoC, и я пытаюсь понять его. Но я не могу понять, как именно это должно применяться с BottomNavigationBar,

Создание списка страниц навигации и установка текущего индекса на событие касания панели навигации приводит к перерисовке всего приложения из-за setState(),

Могу ли я использовать Navigator показывать нажатую навигационную страницу, не теряя панель навигации?

Кто-нибудь использовал шаблон BLoC с BottomNavigationBar? Как мне это сделать? Я хотел бы увидеть пример кода.

1 ответ

Решение

Я наконец получил это. Я помещаю весь код здесь, чтобы помочь другим.

Сначала прочитайте эту замечательную статью от Didier Boelens: https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/

используя его блок провайдера и базовый блок создавать блоки. моя похожа на следующее:

import 'dart:async';
import 'bloc_provider.dart';
import 'package:rxdart/rxdart.dart';

class NewsfeedBloc implements BlocBase {
  BehaviorSubject<int> _ctrl = new BehaviorSubject<int>();

  NewsfeedBloc(
      // listen _ctrl event and do other business logic
  );

  void dispose() {
    _ctrl.close();
  }
}

затем создайте страницу, которая будет использовать блок:

import 'package:flutter/material.dart';
import '../blocs/newsfeed_bloc.dart';
import '../blocs/bloc_provider.dart';

class NewsfeedPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final NewsfeedBloc bloc = BlocProvider.of<NewsfeedBloc>(context);
    // here you should use a stream builder or such to build the ui
    return Container(
      child: Card(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            const ListTile(
              leading: Icon(Icons.album),
              title: Text('The Enchanted Nightingale'),
              subtitle: Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
            ),
            ButtonTheme.bar(
              // make buttons use the appropriate styles for cards
              child: ButtonBar(
                children: <Widget>[
                  FlatButton(
                    child: const Text('BUY TICKETS'),
                    onPressed: () {/* do something with the bloc */},
                  ),
                  FlatButton(
                    child: const Text('LISTEN'),
                    onPressed: () {/* do something with the bloc */},
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

и, наконец, файл main.dart, содержащий навигационную нижнюю панель и ящик:

import 'dart:async';
import 'package:flutter/material.dart';

import 'blocs/bloc_provider.dart';
import 'blocs/application_bloc.dart';
import 'blocs/newsfeed_bloc.dart';
import 'blocs/tracking_bloc.dart';
import 'blocs/notifications_bloc.dart';
import 'blocs/item1_bloc.dart';
import 'blocs/item2_bloc.dart';

import 'pages/newsfeed.dart';
import 'pages/tracking.dart';
import 'pages/notifications.dart';
import 'pages/item1.dart';
import 'pages/item2.dart';

Future<void> main() async {
  return runApp(BlocProvider<ApplicationBloc>(
    bloc: ApplicationBloc(),
    child: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // define your blocs here so that you dont lose the state when your app rebuilds for some reason. thanks boformer for pointing that out.
  NewsfeedBloc _newsfeedBloc;

  PageController _pageController;
  var _page = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Movies',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('App Title'),
        ),
        body: PageView(
          children: <Widget>[
            BlocProvider<NewsfeedBloc>(
              bloc: _newsfeedBloc(),
              child: NewsfeedPage(),
            ),
            // ...
          ],
          controller: _pageController,
          onPageChanged: onPageChanged,
        ),
        bottomNavigationBar: BottomNavigationBar(
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.timeline),
              title: Text("Timeline"),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.art_track),
              title: Text("Some Page"),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.notifications),
              title: Text("Notifications"),
            ),
          ],
          onTap: navigationTapped,
          currentIndex: _page,
        ),
        drawer: Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: <Widget>[
              DrawerHeader(
                child: Text('Settings'),
                decoration: BoxDecoration(
                  color: Colors.blue,
                ),
              ),
              ListTile(
                title: Text('Item 1'),
                onTap: () {
                    Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) { 
                        return BlocProvider<Item1Bloc>(
                            bloc: Item1Bloc(),
                            child: Item1Page(),
                        );
                    }
                },
              ),
              ListTile(
                title: Text('Item 2'),
                onTap: () {
                    Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) { 
                        return BlocProvider<Item2Bloc>(
                            bloc: Item2Bloc(),
                            child: Item2Page(),
                        );
                    }
                },
              ),
            ],
          ),
        ),
      ),
    );
  }

  void navigationTapped(int page) {
    _pageController.animateToPage(
      page,
      duration: Duration(milliseconds: 300),
      curve: Curves.easeIn,
    );
  }

  void onPageChanged(int page) {
    setState(() {
      this._page = page;
    });
  }

  @override
  void initState() {
    super.initState();
    _pageController = new PageController();
    _newsfeedBloc = NewsfeedBloc();    
  }

  @override
  void dispose() {
    super.dispose();
    _pageController.dispose();
  }
}
Другие вопросы по тегам