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

该考虑Provider

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

使用provider是为了更好的进行状态管理,为什么要进行状态管理?当然你怕你组件多了自己瞎搞,乱成一锅粥~

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


效果图

看似理性的分析

  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就够了,

/// 哇靠,怎么和官方的写法有差别!!
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管理,当时有一个什么顾虑,我现在想不起来了,可怕。。继续)

这里我可以看到,只要滚动卡片就会buildChild

拆分组件

刚开始的时候,我们的页面都堆在一个页面里,看起来及其凶残,现在我们来拆分一下,

_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);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

导航栏的菜单也进行的封装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) {
    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是我的页面,空荡荡。。

可以看到,我们使用了ChangeNotifierProvider,当收到buildChild事件后,就会build一个Scaffold而我们的child则会原封不动的放进Scaffold中,避免了重新build

搞定收工

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容