Sliver Appbar [折叠工具栏] 在 Flutter 中从左到中心动画标题

Har*_*rdy 10 android-collapsingtoolbarlayout flutter flutter-sliver

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

     @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"));
      }))
    ],
  ),
);
}
Run Code Online (Sandbox Code Playgroud)

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

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

但我得到的输出为:-

在此输入图像描述

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

问题已在 github 中提交,也可在此处查看。

Pet*_*efe 6

编辑:

我最终创建了一个更好的解决方案,该解决方案利用了FlexibleSpaceBar中已经发生的转换。将文件从要点复制到您的项目后,替换FlexibleSpaceBarMyFlexibleSpaceBar并提供titlePaddingTween诸如

titlePaddingTween: EdgeInsetsTween(begin: EdgeInsets.only(left: 16.0, bottom: 16), end: EdgeInsets.only(left: 72.0, bottom: 16))
Run Code Online (Sandbox Code Playgroud)

而不是标题填充。补间将从应用栏完全展开时的“开始”到应用栏折叠时的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")
        ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Har*_*rdy 3

自己找到了解决办法!!!

将以下代码添加到您的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),
                        ),
                      ),
                    ],
                  );
                },
              ),
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述