Animation 颤振:检测到滚动时隐藏和显示应用程序栏

Animation 颤振:检测到滚动时隐藏和显示应用程序栏,animation,scroll,flutter,appbar,Animation,Scroll,Flutter,Appbar,我在应用程序中使用了SilverAppBar,应用程序栏动画有问题。所以,问题是当我在列表的中间,我向上滚动时,应用程序条不会出现,但是它出现在滚动到达项目列表顶部的时候。我已经测试了snap参数,并给出了true,但不是我期望的结果。我有关于为此创建自定义动画的想法,但我在颤振方面不是很有经验,而且如果有一种方法可以添加参数,或者其他适合我的小部件,那就太好了 我正在使用的演示的实际代码: Widget _search() => Container( color: C

我在应用程序中使用了
SilverAppBar
,应用程序栏动画有问题。所以,问题是当我在列表的中间,我向上滚动时,应用程序条不会出现,但是它出现在滚动到达项目列表顶部的时候。我已经测试了
snap
参数,并给出了
true
,但不是我期望的结果。我有关于为此创建自定义动画的想法,但我在颤振方面不是很有经验,而且如果有一种方法可以添加参数,或者其他适合我的小部件,那就太好了

我正在使用的演示的实际代码:

  Widget _search() => Container(
        color: Colors.grey[400],
        child: SafeArea(
            child: Container(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              enabled: false,
              style: TextStyle(fontSize: 16, color: Colors.white),
              decoration: InputDecoration(
                prefix: SizedBox(width: 12),
                hintText: "Search",
                contentPadding:
                    EdgeInsets.symmetric(horizontal: 32.0, vertical: 14.0),
                border: InputBorder.none,
              ),
            ),
          ),
        )),
      );

  Container _buildBody() {
    return Container(
        child: new GridView.count(
      crossAxisCount: 2,
      children: List.generate(100, (index) {
        return Center(
          child: Text(
            'Item $index',
            style: Theme.of(context).textTheme.headline,
          ),
        );
      }),
    ));
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        resizeToAvoidBottomPadding: false,
        body: new NestedScrollView(
            headerSliverBuilder:
                (BuildContext context, bool innerBoxIsScrolled) {
              return <Widget>[
                new SliverAppBar(
                  title: Text("Demo",
                      style: TextStyle(
                        color: Colors.white,
                      )),
                  pinned: false,
                  floating: true,
                  forceElevated: innerBoxIsScrolled,
                ),
              ];
            },
            body: new Column(children: <Widget>[
              _search(),
              new Expanded(child: _buildBody())
            ])));
  }
Widget\u search()=>容器(
颜色:颜色。灰色[400],
儿童:安全区(
子:容器(
孩子:填充(
填充:常数边集全部(8.0),
孩子:TextField(
启用:false,
样式:TextStyle(字体大小:16,颜色:Colors.white),
装饰:输入装饰(
前缀:SizedBox(宽度:12),
hintText:“搜索”,
内容填充:
边缘组。对称(水平:32.0,垂直:14.0),
边框:InputBorder.none,
),
),
),
)),
);
容器(buildBody){
返回容器(
子项:新建GridView.count(
交叉轴计数:2,
子项:List.generate(100,(索引){
返回中心(
子:文本(
“项目$index”,
风格:Theme.of(context).textTheme.headline,
),
);
}),
));
}
@凌驾
小部件构建(构建上下文){
归还新脚手架(
resizeToAvoidBottomPadding:false,
正文:新嵌套滚动视图(
班主任:
(BuildContext上下文,boolInnerBoxIsCrowled){
返回[
新滑杆(
标题:文本(“演示”,
样式:TextStyle(
颜色:颜色,白色,
)),
错,,
浮动:是的,
强制提升:内包装箱为羊角形,
),
];
},
正文:新列(子项:[
_搜索(),
新扩展的(子:_buildBody())
])));
}
我现在得到的结果是:

true
赋予
snap
参数后得到的结果:


很多应用程序,比如WhatsApp、Facebook、LinkedIn。。。有这个动画应用程序栏。为了更准确地解释我对这个动画应用程序条的期望,我添加了一个Google Play Store的示例,展示了想要的动画:

要让这个功能正常工作,你需要使用
CustomScrollView
小部件,而不是
NestedScrollView

以下是一个工作示例:

class MyHomeState extends State<MyHome> {
@override
Widget build(BuildContext context) {
  return Scaffold(
    body: CustomScrollView(
      slivers: <Widget>[
        const SliverAppBar(
          pinned: false,
          snap: false,
          floating: true,
          flexibleSpace: FlexibleSpaceBar(
            title: Text('Demo'),
          ),
        ),
        SliverGrid(
          gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
            maxCrossAxisExtent: 200.0,
            mainAxisSpacing: 10.0,
            crossAxisSpacing: 10.0,
            childAspectRatio: 4.0,
          ),
          delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              return Container(
                alignment: Alignment.center,
                color: Colors.teal[100 * (index % 9)],
                child: Text('grid item $index'),
              );
            },
            childCount: 50,
          ),
        ),
      ],
    )
  );
}
}
类MyHomeState扩展状态{
@凌驾
小部件构建(构建上下文){
返回脚手架(
正文:自定义滚动视图(
条子:[
常量滑动条(
错,,
快照:错,
浮动:是的,
flexibleSpace:FlexibleSpaceBar(
标题:文本(“演示”),
),
),
银栅(
gridDelegate:SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent:200.0,
主轴间距:10.0,
交叉轴间距:10.0,
childAspectRatio:4.0,
),
代表:SliverChildBuilderDelegate(
(BuildContext上下文,int索引){
返回容器(
对齐:对齐.center,
颜色:Colors.teal[100*(索引%9)],
子项:文本(“网格项$index”),
);
},
儿童人数:50,
),
),
],
)
);
}
}

我在使用刷新指示器的CustomScrollView和SliverAppbar上遇到了类似的问题,我最终创建了自己的自定义appbar。

    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';

    class HomeView extends StatefulWidget {
      @override
      HomeState createState() => HomeState();
    }

    class HomeState extends State<HomeView> with SingleTickerProviderStateMixin {
      bool _isAppbar = true;
      ScrollController _scrollController = new ScrollController();

      @override
      void initState() {
        super.initState();
        _scrollController.addListener(() {
          if (_scrollController.position.userScrollDirection ==
              ScrollDirection.reverse) {
            appBarStatus(false);
          }
          if (_scrollController.position.userScrollDirection ==
              ScrollDirection.forward) {
            appBarStatus(true);
          }
        });
      }

      void appBarStatus(bool status) {
        setState(() {
          _isAppbar = status;
        });
      }

      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Scaffold(
            appBar: PreferredSize(
              preferredSize: Size.fromHeight(kToolbarHeight),
              child: AnimatedContainer(
                height: _isAppbar ? 55.0 : 0.0,
                duration: Duration(milliseconds: 200),
                child: CustomAppBar(),
              ),
            ),
            body: ListView.builder(
              controller: _scrollController,
              itemCount: 20,
              itemBuilder: (BuildContext context, int index) {
                return container();
              },
            ),
          ),
        );
      }
    }

    Widget container() {
      return Container(
        height: 80.0,
        color: Colors.pink,
        margin: EdgeInsets.all(8.0),
        width: 100,
        child: Center(
            child: Text(
          'Container',
          style: TextStyle(
            fontSize: 18.0,
          ),
        )),
      );
    }

    class CustomAppBar extends StatefulWidget {
      @override
      AppBarView createState() => new AppBarView();
    }

    class AppBarView extends State<CustomAppBar> {
      @override
      Widget build(BuildContext context) {
        return AppBar(
          backgroundColor: Colors.white,
          leading: InkWell(
            onTap: () => {},
            child: new Padding(
              padding: const EdgeInsets.all(8.0),
              child: CircleAvatar(
                backgroundColor: Colors.white,
                child: ClipOval(
                  child: Image.network(
                      'https://images.squarespace-cdn.com/content/5aee389b3c3a531e6245ae76/1530965251082-9L40PL9QH6PATNQ93LUK/linkedinPortraits_DwayneBrown08.jpg?format=1000w&content-type=image%2Fjpeg'),
                ),
              ),
            ),
          ),
          actions: <Widget>[
            IconButton(
              alignment: Alignment.centerLeft,
              icon: Icon(
                Icons.search,
                color: Colors.black,
              ),
              onPressed: () {},
            ),
          ],
          title: Container(
            alignment: Alignment.centerLeft,
            child: Text("Custom Appbar", style: TextStyle(color: Colors.black),)
          ),
        );
      }
    }
导入“包装:颤振/材料.省道”;
导入“package:flatter/rendering.dart”;
类HomeView扩展了StatefulWidget{
@凌驾
HomeState createState()=>HomeState();
}
类HomeState使用SingleTickerProviderStateMixin扩展状态{
bool_isAppbar=true;
ScrollController_ScrollController=新的ScrollController();
@凌驾
void initState(){
super.initState();
_scrollController.addListener((){
如果(_scrollController.position.userScrollDirection==
滚动方向(反向){
appBarStatus(假);
}
如果(_scrollController.position.userScrollDirection==
滚动方向(前进){
appBarStatus(真实);
}
});
}
无效appBarStatus(布尔状态){
设置状态(){
_isAppbar=状态;
});
}
@凌驾
小部件构建(构建上下文){
返回安全区(
孩子:脚手架(
appBar:首选大小(
preferredSize:Size.fromHeight(kToolbarHeight),
子:动画容器(
高度:_isAppbar?55.0:0.0,
持续时间:持续时间(毫秒:200),
子项:CustomAppBar(),
),
),
正文:ListView.builder(
控制器:\ u滚动控制器,
物品计数:20,
itemBuilder:(构建上下文,int索引){
返回容器();
},
),
),
);
}
}
小部件容器(){
返回容器(
身高:80.0,
颜色:颜色。粉红色,
边距:所有边集(8.0),
宽度:100,
儿童:中心(
子:文本(
"货柜",,
import 'dart:math';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: CustomSliverAppbar(),
    );
  }
}

class CustomSliverAppbar extends StatefulWidget {
  @override
  _CustomSliverAppbarState createState() => _CustomSliverAppbarState();
}

class _CustomSliverAppbarState extends State<CustomSliverAppbar>
    with SingleTickerProviderStateMixin {
  TabController _tabController;

  @override
  void initState() {
    _tabController = TabController(
      initialIndex: 0,
      length: 2,
      vsync: this,
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        floatHeaderSlivers: true,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: Text(
                "WhatsApp type sliver appbar",
              ),
              centerTitle: true,
              pinned: true,
              floating: true,
              bottom: TabBar(
                  indicatorColor: Colors.black,
                  labelPadding: const EdgeInsets.only(
                    bottom: 16,
                  ),
                  controller: _tabController,
                  tabs: [
                    Text("TAB A"),
                    Text("TAB B"),
                  ]),
            ),
          ];
        },
        body: TabBarView(
          controller: _tabController,
          children: [
            TabA(),
            const Center(
              child: Text('Display Tab 2',
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }
}

class TabA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scrollbar(
      child: ListView.separated(
        separatorBuilder: (context, child) => Divider(
          height: 1,
        ),
        padding: EdgeInsets.all(0.0),
        itemCount: 30,
        itemBuilder: (context, i) {
          return Container(
            height: 100,
            width: double.infinity,
            color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
          );
        },
      ),
    );
  }
}