SliverAppBar с floating:true не разворачивается если начать скролить вниз
Когда я скролю список не с самого верха (есть элементы выше) SliverAppBar не будет отображаться до тех пор пока я не достигну верхней части списка, но в Telegram, AppBar начинает показываться сразу после того как я начинаю скролить вниз.
Я хочу достичь того же поведения что и AppBar в Telegram.
Хотелось бы уточнить что snap: true дает похожее, но не то поведение кторое нужно.
Вот код который у меня сейчас есть (Живой пример):
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
TestPage({Key? key, this.title}) : super(key: key);
final String? title;
@override
_TestPageState createState() => _TestPageState();
}
class TabElement {
String id;
int? count;
String? label;
TabElement({required this.id, this.count, this.label}) {
label ??= id;
}
}
class Element {
late String id;
}
class _TestPageState extends State<TestPage> {
final Map<String, List<Element>?> _orders = {
'step1': null,
'step2': null,
'step3': null,
'step4': null,
'step5': null,
'step6': null,
'step7': null,
'step8': null,
'step9': null,
'step10': null,
'step11': null,
'step12': null,
'step13': null,
'step14': null,
};
List<TabElement> get _tabs => _orders.entries
.map((el) => TabElement(id: el.key, count: el.value?.length))
.toList();
@override
Widget build(BuildContext context) {
return Scaffold(
body: DefaultTabController(
length: _tabs.length,
child: _nestedScrollView(widget, _tabs, _orders),
),
);
}
}
Widget _tab(TabElement tab) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (tab.label != null)
Text(
tab.label as String,
style: TextStyle(color: Colors.black),
),
],
);
}
Widget _nestedScrollView(TestPage widget, List<TabElement> tabs, orders) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: _sliverAppBar(context, widget, innerBoxIsScrolled, tabs),
),
];
},
body: _tabBarView(tabs, orders),
);
}
Widget _sliverAppBar(BuildContext context, TestPage widget,
bool innerBoxIsScrolled, List<TabElement> tabs) {
return SliverAppBar(
title: Text(
widget.title as String,
style: TextStyle(color: Colors.black),
),
centerTitle: false,
backgroundColor: Colors.white,
pinned: true,
floating: true,
snap: false,
forceElevated: innerBoxIsScrolled,
bottom: TabBar(
isScrollable: true,
tabs:
tabs.map<Widget>((TabElement tab) => Tab(child: _tab(tab))).toList(),
),
);
}
Widget _tabBarView(List<TabElement> tabs, orders) {
return TabBarView(
children: tabs
.map<Widget>((tab) => SafeArea(
top: false,
bottom: false,
child: Builder(builder: (BuildContext context) {
return CustomScrollView(
key: PageStorageKey<String>(tab.id),
slivers: <Widget>[
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
),
SliverFixedExtentList(
itemExtent: 48.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(
title: Text('Item $index'),
);
},
childCount: 80,
),
),
],
);
})))
.toList());
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: TestPage(title: 'Test'),
);
}
}
Ответы (1 шт):
Автор решения: Vasiliy Rusin
→ Ссылка
Ответ оказался поразительно прост. У NestedScrollView есть метод floatHeaderSlivers, он и добавляет необходимое поведение.
NestedScrollView(
floatHeaderSlivers: true,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[];
},
body: _tabBarView(tabs, orders),
)
