flutter - 像 SliverAppBar 一样隐藏 TabBar
问题描述
所以网上有很多例子,你可以使用SliverAppBar
隐藏在滚动上的 a,TabBar
下面仍然显示。我找不到任何相反的方法:当我向上滚动时,我只想隐藏TabBar
AppBar
,始终保持持续显示。有谁知道如何实现这一目标?
这是一个隐藏 AppBar 的示例(这不是我想要的,只是有助于更好地理解我想要的)。
更新
这是我迄今为止尝试过的,我认为它有效,但问题是我无法AppBar
在Positioned
现场获得正确的高度(例如,iPhone X 它的高度更大并且与标签栏重叠)。
// this sliver app bar is only use to hide/show the tabBar, the AppBar
// is invisible at all times. The to the user visible AppBar is below
return Scaffold(
body: Stack(
children: <Widget>[
NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
floating: true,
snap: true,
pinned: false,
bottom: TabBar(
tabs: [
Tab(
child: Text(
"1",
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"2",
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"3",
textAlign: TextAlign.center,
),
),
],
controller: _tabController,
),
),
];
},
body: TabBarView(
children: [
MyScreen1(),
MyScreen2(),
MyScreen3(),
],
controller: _tabController,
physics: new NeverScrollableScrollPhysics(),
),
),
// Here is the AppBar the user actually sees. The SliverAppBar
// above will slide the TabBar underneath this one. However,
// I can´t figure out how to give it the correct height.
Container(
child: Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(
iconTheme: IconThemeData(
color: Colors.red, //change your color here
),
automaticallyImplyLeading: true,
elevation: 0,
title: Text("My Title"),
centerTitle: true,
),
),
),
],
),
);
解决方案
这是您如何做到这一点的方法,想法是在 apostframecallback
的帮助下使用 aGlobalKey
来预先计算appBar height
并在下面添加exapandedHeight
类似的,
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
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 {
TabController _tabController;
GlobalKey _appBarKey;
double _appBarHight;
@override
void initState() {
_appBarKey = GlobalKey();
_tabController = TabController(length: 3, vsync: this);
SchedulerBinding.instance.addPostFrameCallback(_calculateAppBarHeight);
super.initState();
}
_calculateAppBarHeight(_){
final RenderBox renderBoxRed = _appBarKey.currentContext.findRenderObject();
setState(() {
_appBarHight = renderBoxRed.size.height;
});
print("AppbarHieght = $_appBarHight");
}
@override
Widget build(BuildContext context) {
// this sliver app bar is only use to hide/show the tabBar, the AppBar
// is invisible at all times. The to the user visible AppBar is below
return Scaffold(
body: Stack(
children: <Widget>[
NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
floating: true,
expandedHeight: _appBarHight,
snap: true,
pinned: false,
bottom: TabBar(
tabs: [
Tab(
child: Text(
"1",
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"2",
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"3",
textAlign: TextAlign.center,
),
),
],
controller: _tabController,
),
),
];
},
body: TabBarView(
children: [
MyScreen1(),
MyScreen2(),
MyScreen3(),
],
controller: _tabController,
physics: new NeverScrollableScrollPhysics(),
),
),
// Here is the AppBar the user actually sees. The SliverAppBar
// above will slide the TabBar underneath this one. However,
// I can¥t figure out how to give it the correct height.
Container(
key: _appBarKey,
child: Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(
backgroundColor: Colors.red,
iconTheme: IconThemeData(
color: Colors.red, //change your color here
),
automaticallyImplyLeading: true,
elevation: 0,
title: Text("My Title"),
centerTitle: true,
),
),
),
],
),
);
}
}
class MyScreen1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("My Screen 1"),
),
);
}
}
class MyScreen2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("My Screen 2"),
),
);
}
}
class MyScreen3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("My Screen 3"),
),
);
}
}
编辑:
经过更多调查,我发现了一个没有键或 MediaQuery “东西”的解决方案,只使用SafeArea
Widget 。请检查以下完整代码:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
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 {
TabController _tabController;
@override
void initState() {
_tabController = TabController(length: 3, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
// this sliver app bar is only use to hide/show the tabBar, the AppBar
// is invisible at all times. The to the user visible AppBar is below
return Scaffold(
body: Stack(
children: <Widget>[
NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
primary: true,
floating: true,
backgroundColor: Colors.blue,//.withOpacity(0.3),
snap: true,
pinned: false,
bottom: TabBar(
tabs: [
Tab(
child: Text(
"1",
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"2",
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"3",
textAlign: TextAlign.center,
),
),
],
controller: _tabController,
),
),
];
},
body: TabBarView(
children: [
MyScreen1(),
MyScreen2(),
MyScreen3(),
],
controller: _tabController,
physics: new NeverScrollableScrollPhysics(),
),
),
// Here is the AppBar the user actually sees. The SliverAppBar
// above will slide the TabBar underneath this one.
// by using SafeArea it will.
Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: Container(
child: SafeArea(
top: false,
child: AppBar(
backgroundColor: Colors.blue,
// iconTheme: IconThemeData(
// color: Colors.red, //change your color here
// ),
automaticallyImplyLeading: true,
elevation: 0,
title: Text("My Title",),
centerTitle: true,
),
),
),
),
],
),
);
}
}
class MyScreen1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
child: Center(
child: Text("My Screen 1"),
),
);
}
}
class MyScreen2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("My Screen 2"),
),
);
}
}
class MyScreen3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("My Screen 3"),
),
);
}
}
推荐阅读
- java - Unable to perform Uber login programmatically
- php - Using Symfony Messenger without framework
- r - 当连接附加了后缀时,如何在函数中引用用户输入的列名 post join?
- python - How do I build convolutional neural network using OptionsDataset
- oracle - Oracle中如何同步线程?
- spring-boot - How to get initial data using Spring RabbitMQ and websockets
- r - R Boxpacker 函数未显示 3d 可视化
- python - Pandas 根据列将多行合并为一行
- c++ - 为什么动态数组的地址与第一个元素的地址不同?
- node.js - Sequelize Associations - 关联表