--- 编辑 1 --
好的,我为您快速整理了一些东西。我参考了这篇文章(由 Emily Fortuna 撰写,她是 Flutter 的主要开发人员之一),以更好地理解 Slivers。
Medium: Slivers, Demystified
然后我找到了这个 YouTube 视频,基本上使用了您的代码,所以我选择了它,而不是尝试弄清楚关于 Slivers 的每一个细节。
Youtube: Using Tab and Scroll Controllers and the NestedScrollView in Dart's Flutter Framework
结果证明,您的代码方向是正确的。您可以在 NestedScrollView
中使用 SliverAppBar
(上次我尝试时还不行),但我做了一些改变。我会在我的代码之后解释:
import 'package:flutter/material.dart';
import 'dart:math';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin /*<-- This is for the controllers*/ {
TabController _tabController;
ScrollController _scrollViewController;
List<String> items = [];
List<Color> colors = [Colors.red, Colors.green, Colors.yellow, Colors.purple, Colors.blue, Colors.amber, Colors.cyan, Colors.pink];
Random random = new Random();
Color getRandomColor() {
return colors.elementAt(random.nextInt(colors.length));
}
@override
void initState() {
super.initState();
_tabController =TabController(vsync: this, length: 2);
_scrollViewController =ScrollController();
}
@override
void dispose() {
super.dispose();
_tabController.dispose();
_scrollViewController.dispose();
}
@override
Widget build(BuildContext context) {
for (var i = 0; i < 100; i++) {
items.add('Item $i');
}
return SafeArea(
child: NestedScrollView(
controller: _scrollViewController,
headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
return <Widget>[
SliverAppBar(
title: Text("WhatsApp using Flutter"),
floating: true,
pinned: false,
snap: true,
bottom: TabBar(
tabs: <Widget>[
Tab(
child: Text("Colors"),
),
Tab(
child: Text("Chats"),
),
],
controller: _tabController,
),
),
];
},
body: TabBarView(
controller: _tabController,
children: <Widget>[
ListView.builder(
itemBuilder: (BuildContext context, int index) {
Color color = getRandomColor();
return Container(
height: 150.0,
color: color,
child: Text(
"Row $index",
style: TextStyle(
color: Colors.white,
),
),
);
},
),
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Material(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blueGrey,
),
title: Text(
items.elementAt(index)
),
),
);
},
),
],
),
),
);
}
}
好的,现在开始解释。
使用 StatefulWidget
Flutter 中的大多数小部件都将是有状态的,但这取决于情况。在这种情况下,我认为最好使用一个StatefulWidget
,因为您正在使用可能随用户添加或删除对话/聊天而更改的ListView
。
使用 SafeArea
小部件。
请在Flutter Docs:SafeArea 上阅读它。
控制器
我认为刚开始这可能是个大问题,但也许还有其他什么问题。但是,如果您正在处理 Flutter 中的自定义行为,则通常应自己创建控制器。因此,我制作了_tabController
和_scrollViewController
(我认为我没有完全利用它们的所有功能,例如在选项卡之间跟踪滚动位置,但它们适用于基础知识)。用于TabBar
和TabView
的选项卡控制器应该相同。
ListTile
前的 Material
小部件
您可能迟早会发现这一点,但是ListTile
小部件是一个Material小部件,因此根据我首次尝试呈现它时得到的输出,需要"Material祖先小部件"。所以我为您解决了一个微小的头痛。我认为这是因为我没有使用Scaffold
。(在使用没有材料祖先小部件的材料小部件时,请记住这一点)
希望这能帮助你入门,如果需要任何帮助,请给我发消息或将我添加到你的Github仓库中,我会尽力帮忙。
--- 翻译 ---
我在 Reddit 上也回答了你,希望你能尽快看到其中之一。
SliverAppBar 信息
SliverAppBar 的关键属性包括:
floating: Whether the app bar should become visible as soon as the user scrolls towards the app bar.
pinned: Whether the app bar should remain visible at the start of the scroll view. (This is the one you are asking about)
snap: If snap and floating are true then the floating app bar will "snap" into view.
这些内容来自Flutter SliverAppBar文档。它们有许多不同的浮动、固定和快照组合的动画示例。
因此,对于您的应用程序,以下内容应该有效:
SliverAppBar(
title: Text("Application"),
floating: true,
pinned: false,
snap: true,
bottom: new TabBar(
tabs: [ ... ],
),
),
ScrollView与SliverAppBar
回答关于NestedScrollView
的潜在问题。根据文档(同上),SliverAppBar
是:
与CustomScrollView
集成的材料设计应用栏。
因此,您不能使用NestedScrollView
,您需要使用CustomScrollView
。这是Sliver
类的预期用途,但它们也可以在NestedScrollView
中使用。请查看文档。