用 Flutter 水一个可丑的渐变首页(二)

该考虑Provider

官方说好用,那么用就是了~bash

使用provider是为了更好的进行状态管理,为何要进行状态管理?固然你怕你组件多了本身瞎搞,乱成一锅粥~markdown

没图啊,效果图再贴一遍吧,狗带 less

效果图

看似理性的分析

  1. 要时间滚动日记卡片的时候,下面的导航按钮随着改变颜色,导航栏就必须知道,当前滚到第几页(double)了,才能作出相应的改变
  2. 导航栏和日记卡片使用相同的色盘:
    /// 色盘: 写两个意思一下,十二个月,应该有十二个。。
     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),
         ],
     ];
    复制代码
  3. 日记卡片在滚动的时候尽可能减小其余组件的build
  4. 底部导航要写渐变更画吗?不用,卡片的滚动会通知到导航栏,使其从新build,只要我build的足够快,你的眼睛就跟不上我。。。动画也不是这么搞的嘛,笑摸我狗头~

provider走起来

有了上面的分析,咱们的provider只要通知page就够了,ide

/// 哇靠,怎么和官方的写法有差异!!
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 get value => _ctrl?.page ?? 0;

  int _curPage = 0;

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

  void buildChild() {
    notifyListeners();
  }
 }
复制代码

哇靠,怎么和官方的写法有差异!!其实没什么差异,只是咱们有一个addListener的操做,而咱们的PageController不是由HomeState来管理的。(实际上是能够放在HomeState管理,当时有一个什么顾虑,我如今想不起来了,可怕。。继续)动画

这里我能够看到,只要滚动卡片就会buildChildui

拆分组件

刚开始的时候,咱们的页面都堆在一个页面里,看起来及其凶残,如今外面来拆分一下,this

_FloatBtnWidget悬浮的添加按钮

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),
    );
  }
}
复制代码

_BottomNavWidget底部导航栏

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);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
复制代码

导航栏的菜单也进行的封装GradientIconBtnspa

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) {
    return IconButton(
      onPressed: onPress,
      icon: gradient == null
          ? Icon(icon, size: iconSize)
          : GradientText(
              iconData: icon,
              iconSize: iconSize,
              gradient: selected ? selectedGradient : gradient,
            ),
    );
  }
}
复制代码

最终组装ChangeNotifierProvider

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),
    ),
  ),
)
复制代码

NoteYearViewPage是卡片页面,比较简单,写死的渐变。MinePage是个人页面,空荡荡。。code

能够看到,咱们使用了ChangeNotifierProvider,当收到buildChild事件后,就会build一个Scaffold而咱们的child则会原封不动的放进Scaffold中,避免了从新buildcdn

搞定收工

好像完成了,呵呵呵~贴代码真是爽,整个过程只要28分钟。。 中间有一些小细节可能没有说明,想了解的小伙伴能够查看源码: gayhub

相关文章
相关标签/搜索