【问题标题】:Sliver Appbar [Collapsing Toolbar] animate title from left to center in FlutterSliver Appbar [Collapsing Toolbar] 在 Flutter 中从左到中动画标题
【发布时间】:2020-04-02 05:46:25
【问题描述】:

这是我的折叠工具栏的构建方法:-

     @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: CustomScrollView(
        controller: controller,
        slivers: <Widget>[
          SliverAppBar(
            pinned: true,
            expandedHeight: appBarHeight,
            leading: IconButton(
              icon: Icon(
                Icons.arrow_back_ios,
                color: Colors.black,
              ),
              onPressed: () => null,
            ),
            floating: true,
            flexibleSpace: FlexibleSpaceBar(

          titlePadding: EdgeInsets.only(left:leftV , bottom:bottomV ),
          title: Text(
            "Title ",
            style: TextStyle(
              color: Colors.black,
              fontSize: 16.0,
            ),
          ),
        ),
      ),
      SliverList(delegate:
          SliverChildBuilderDelegate((BuildContext context, int index) {
        return ListTile(title: Text("Flutter / $index"));
      }))
    ],
  ),
);
}

根据文档,我得到了删除填充的解决方案:-

/// 默认情况下该属性的值为 /// EdgeInsetsDirectional.only(start: 72, bottom: 16) 如果标题是 /// 不居中,EdgeInsetsDirectional.only(start 0, bottom: 16) 否则。 final EdgeInsetsGeometry titlePadding;

但我得到的输出是:-

当应用栏完全折叠时,我想将标题居中。

问题也已在 github 中提交check here.

【问题讨论】:

    标签: flutter android-collapsingtoolbarlayout flutter-sliver


    【解决方案1】:

    我自己找到了解决方案!!!

    将以下代码添加到您的 Sliver 应用栏 .........

     flexibleSpace: LayoutBuilder(
                    builder:
                        (BuildContext context, BoxConstraints constraints) {
                      double percent =
                          ((constraints.maxHeight - kToolbarHeight) *
                              100 /
                              (appBarHeight - kToolbarHeight));
                      double dx = 0;
    
                      dx = 100 - percent;
                      if (constraints.maxHeight == 100) {
                        dx = 0;
                      }
    
                      return Stack(
                        children: <Widget>[
                          Padding(
                            padding: const EdgeInsets.only(
                                top: kToolbarHeight / 4, left: 0.0),
                            child: Transform.translate(
                              child: Text(
                                title,
                                style: MyTextStyle.getAppBarTextStyle(
                                    screenUtil, appColors),
                              ),
                              offset: Offset(
                                  dx, constraints.maxHeight - kToolbarHeight),
                            ),
                          ),
                        ],
                      );
                    },
                  ),
    

    百分比是根据滚动计算的,并相应地放置动画。

    【讨论】:

    • 这不能正常工作,也许你可以留下一些 cmets 来解释你的代码
    • @umni4ek 您可能需要使用 MediaQuery.of(context).size.width 和 MediaQuery.of(context).size.height 来设置您的条子高度和其他计算。这样所有屏幕尺寸都会适当调整。
    【解决方案2】:

    我设法通过ScrollController 找到了解决方案。

    Example Result Gif

    我使用了下一个函数:

    double get _horizontalTitlePadding {
        const kBasePadding = 15.0;
        const kMultiplier = 0.5;
    
        if (_scrollController.hasClients) {
          if (_scrollController.offset < (kExpandedHeight / 2)) {
            // In case 50%-100% of the expanded height is viewed
            return kBasePadding;
          }
    
          if (_scrollController.offset > (kExpandedHeight - kToolbarHeight)) {
            // In case 0% of the expanded height is viewed
            return (kExpandedHeight / 2 - kToolbarHeight) * kMultiplier +
                kBasePadding;
          }
    
          // In case 0%-50% of the expanded height is viewed
          return (_scrollController.offset - (kExpandedHeight / 2)) * kMultiplier +
              kBasePadding;
        }
    
        return kBasePadding;
    }
    

    我在 SilverAppBar titlePadding 内部使用了它:

      child: Scaffold(
          body: CustomScrollView(
        controller: _scrollController,
        slivers: <Widget>[
          SliverAppBar(
            pinned: true,
            expandedHeight: kExpandedHeight,
            flexibleSpace: FlexibleSpaceBar(
              titlePadding: EdgeInsets.symmetric(
                  vertical: 16.0, horizontal: _horizontalTitlePadding),
    

    只需确保在initState() 中初始化控制器:

    _scrollController = ScrollController()..addListener(() => setState(() {}));
    

    【讨论】:

      【解决方案3】:

      编辑:

      我最终创建了 a better solution,它利用了 FlexibleSpaceBar 中已经发生的转换。将文件从 gist 复制到项目后,将 FlexibleSpaceBar 替换为 MyFlexibleSpaceBar 并提供 titlePaddingTween 例如

      titlePaddingTween: EdgeInsetsTween(begin: EdgeInsets.only(left: 16.0, bottom: 16), end: EdgeInsets.only(left: 72.0, bottom: 16))
      

      而不是titlePadding。补间动画将从应用栏完全展开时的“开始”EdgeInsets 动画到应用栏折叠时的“结束”EdgeInsets

      我还添加了一个foreground 参数,显示在标题和背景上方,但不会像它们那样变换。

      原答案:

      其他答案很好,但它们重建的小部件比必要的多。我的解决方案建立在其他答案的基础上,但只会重建 ValueListenableBuilder 中的内容:

      class SamplePage extends StatelessWidget {
        static const _kBasePadding = 16.0;
        static const kExpandedHeight = 250.0;
      
        final ValueNotifier<double> _titlePaddingNotifier = ValueNotifier(_kBasePadding);
      
        final _scrollController = ScrollController();
      
        double get _horizontalTitlePadding {
          const kCollapsedPadding = 60.0;
      
          if (_scrollController.hasClients) {
            return min(_kBasePadding + kCollapsedPadding,
                _kBasePadding + (kCollapsedPadding * _scrollController.offset)/(kExpandedHeight - kToolbarHeight));
          }
      
          return _kBasePadding;
        }
      
        @override
        Widget build(BuildContext context) {
          _scrollController.addListener(() {
            _titlePaddingNotifier.value = _horizontalTitlePadding;
          });
      
          return Scaffold(
      
            body: NestedScrollView(
                controller: _scrollController,
                headerSliverBuilder: (context, innerBoxIsScrolled) {
                  return <Widget>[
                    SliverAppBar(
                        expandedHeight: kExpandedHeight,
                        floating: false,
                        pinned: true,
                        flexibleSpace: FlexibleSpaceBar(
                            collapseMode: CollapseMode.pin,
                            centerTitle: false,
                            titlePadding: EdgeInsets.symmetric(vertical: 16, horizontal: 0),
                            title: ValueListenableBuilder(
                              valueListenable: _titlePaddingNotifier,
                              builder: (context, value, child) {
                                return Padding(
                                  padding: EdgeInsets.symmetric(horizontal: value),
                                  child: Text(
                                    "Title"),
                                );
                              },
                            ),
                            background: Container(color: Colors.green)
                        )
                    ),
                  ];
                },
                body: Text("Body text")
              ),
          );
        }
      }
      

      【讨论】:

      • 我确实最终更改了我在自己的应用程序中发布的代码以进行性能优化,确实最好只在必要时重建。
      • 如果有人知道这个人做对了,那么与其他答案相比,这个答案是最好的
      • 谢谢,编辑的答案有效。我用过 MyFlexibleSpaceBar 并且像冠军一样工作。你拯救了我的一天。
      猜你喜欢
      • 2021-07-27
      • 2020-03-13
      • 1970-01-01
      • 1970-01-01
      • 2021-02-09
      • 1970-01-01
      • 2020-11-17
      • 2019-06-04
      • 2020-12-26
      相关资源
      最近更新 更多