The considerationProviderthe

Official says it works, so just use it

The purpose of using a provider is to better manage the status. Why do YOU need to manage the status? Of course, you are afraid of your component more than their own mess, chaos into a pot of porridge ~

There is no picture, the effect picture is posted again, dog belt

Seemingly rational analysis

  1. In order to scroll through the diary card, the navigation button below must know the current page as it changes color.double) in order to make corresponding changes
  2. Use the same color palette for navigation and journal cards:
    /// Color plate: Write two meanings, twelve months, there should be twelve.
     static const List<List<Color>> linerColor = [
         [
           Color.fromARGB(255.87.211.255),
           Color.fromARGB(255.86.173.254),
         ],
         [
           Color.fromARGB(255.86.173.254),
           Color.fromARGB(255.82.118.254),]];Copy the code
  3. Diary cards minimize other components when scrollingbuild
  4. Do I want to animate the gradient in the bottom navigation? No, the scrolling of the card will notify the navigation bar, making it re-runbuildAs long as IbuildFast enough, your eyes won’t follow me… Animation is not so do, laugh touch my dog head ~

providerGo up

With the above analysis, our provider simply notifies the page,

/// What is the difference?
class HomeState with ChangeNotifier {
  HomeState(this._ctrl) : assert(_ctrl ! =null) {
    _ctrl.addListener(() {
      _curPage = _ctrl.page.floor();
      notifyListeners();
    });
  }

  final PageController _ctrl;

  int get curPage => _curPage;

  double getvalue => _ctrl? .page ??0;

  int _curPage = 0;

  void setPage(int index) {
    _curPage = index;
    notifyListeners();
  }

  voidbuildChild() { notifyListeners(); }}Copy the code

Wow depend, how and the official writing method have difference!! There is no difference, except that we have an addListener operation and our PageController is not managed by HomeState. (In fact, it can be put in HomeState management, there was a concern, I can’t remember now, terrible. Continue)

And here I can see that whenever I scroll the card it will buildChild.

Break up the component

When we started, our pages were all on one page, and it looked like it was going to be horrible, but now let’s break it up outside,

_FloatBtnWidgetHover add button

class _FloatBtnWidget extends StatelessWidget {
  _FloatBtnWidget(this._homeProvider);

  final HomeState _homeProvider;

  @override
  Widget build(BuildContext context) {
    double cil = _homeProvider.value - _homeProvider.value.floor();
    double lerp = cil == 0 ? 1 : cil;
    return Container(
      width: 56,
      height: 56,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [
            Color.lerp(
              StaticStyle.linerColor[_homeProvider.curPage][0],
              StaticStyle.linerColor[_homeProvider.value.ceil()][0],
              lerp,
            ),
            Color.lerp(
              StaticStyle.linerColor[_homeProvider.curPage][1],
              StaticStyle.linerColor[_homeProvider.value.ceil()][1],
              lerp,
            ),
          ],
        ),
        boxShadow: [
          BoxShadow(
            color: Color.fromARGB(100.87.211.255),
            blurRadius: 8, ) ], ), child: Icon(Icons.add, color: Colors.white), ); }}Copy the code

_BottomNavWidgetBottom navigation bar


class _BottomNavWidget extends StatelessWidget {
  _BottomNavWidget(this._homeProvider, this.tabState);

  final TabState tabState;
  final HomeState _homeProvider;

  @override
  Widget build(BuildContext context) {
    double cil = _homeProvider.value - _homeProvider.value.floor();
    double lerp = cil == 0 ? 1 : cil;

    final Gradient gradient = LinearGradient(
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
      colors: [
        Colors.black54,
        Colors.black,
      ],
    );

    final Gradient selectedGradient = LinearGradient(
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
      colors: [
        Color.lerp(
          StaticStyle.linerColor[_homeProvider.curPage][0],
          StaticStyle.linerColor[_homeProvider.value.ceil()][0],
          lerp,
        ),
        Color.lerp(
          StaticStyle.linerColor[_homeProvider.curPage][1],
          StaticStyle.linerColor[_homeProvider.value.ceil()][1],
          lerp,
        ),
      ],
    );

    return DecoratedBox(
      decoration: BoxDecoration(boxShadow: [
        BoxShadow(
          color: Color.fromARGB(100.200.200.200),
          blurRadius: 8,
        )
      ]),
      child: ClipRRect(
        borderRadius: BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)),
        child: BottomAppBar(
          elevation: 0,
          notchMargin: 6,
          shape: CircularNotchedRectangle(),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              GradientIconBtn(
                Icons.note_add,
                key: ValueKey('page-index-0'),
                iconSize: 26,
                gradient: gradient,
                selectedGradient: selectedGradient,
                selected: tabState.tabIndex == 0,
                onPress: () {
                  tabState.setTab(0);
                },
              ),
              Text(' '),
              GradientIconBtn(
                Icons.person,
                key: ValueKey('page-index-1'),
                iconSize: 26,
                gradient: gradient,
                selectedGradient: selectedGradient,
                selected: tabState.tabIndex == 1,
                onPress: () {
                  tabState.setTab(1); }, [, [, (), (), (), (); }}Copy the code

The navigation bar menu also carries the encapsulation GradientIconBtn:

class GradientIconBtn extends StatelessWidget {
  GradientIconBtn(
    this.icon, {
    Key key,
    @required this.onPress,
    this.iconSize,
    this.gradient,
    this.selectedGradient,
    this.selected = false,
  }) : super(key: key);

  final VoidCallback onPress;
  final IconData icon;
  final double iconSize;
  final Gradient gradient;
  final Gradient selectedGradient;
  final bool selected;

  @override
  Widget build(BuildContext context) {
    returnIconButton( onPressed: onPress, icon: gradient == null ? Icon(icon, size: iconSize) : GradientText( iconData: icon, iconSize: iconSize, gradient: selected ? selectedGradient : gradient, ), ); }}Copy the code

Final assemblyChangeNotifierProvider:

ChangeNotifierProvider<HomeState>(
  builder: (_) => HomeState(_pageController),
  child: Consumer<HomeState>(
    child: IndexedStack(
      index: widget.tabState.tabIndex,
      children: <Widget>[
        NoteYearViewPage(_pageController),
        MinePage(),
      ],
    ),
    builder: (_, HomeState homeProvider, Widget child) => Scaffold(
      body: child,
      floatingActionButton: _FloatBtnWidget(homeProvider),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: _BottomNavWidget(homeProvider, widget.tabState),
    ),
  ),
)
Copy the code

NoteYearViewPage is a card page, simple, write dead gradient. MinePage is my page, empty..

As you can see, we use the ChangeNotifierProvider. When we receive the buildChild event, a Scaffold is built and our child is put into that Scaffold intact, avoiding the need to build again.

Do call it a day

Seems to be done, ha ha ha ~ paste code is really cool, the whole process only takes 28 minutes. There are a few minor details that may not be explained, but you can check out the source code: gayHub