[英]How can i add gradient to a SliverAppBar, but only when it's collapsed?
[英]How to make floating SliverAppBar to show only collapsed bar?
我正在使用带有背景图像的 Flutter Web 的 SliverAppBar,我希望该栏在用户向下滚动网页时消失,并在他们向上滚动时再次出现,但只有应用程序栏,不显示背景,除非他们到达顶峰。 这在 Flutter web 中可以实现吗?
我的 SliverAppBar:
class NavBar extends StatelessWidget {
final Widget _background;
const NavBar(this._background);
@override
SliverAppBar build(BuildContext context) {
double _width = MediaQuery.of(context).size.width;
double? _height = MediaQuery.of(context).size.height;
List<Widget> _actions() {
List<Widget> _list = [];
List _titles = Navigation(context).routes.keys.toList();
List _routes = Navigation(context).routes.values.toList();
_selectView(String route) {
Navigator.of(context).pushNamed(route);
}
Widget _singleItem(String text, String route) {
return InkWell(
onTap: () => _selectView(route),
borderRadius: BorderRadius.circular(15),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
alignment: Alignment.center,
child: Text(
text,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
);
}
for (int i = 0; i < Navigation(context).showingLinks; i++) {
_list.add(_singleItem(_titles[i], _routes[i]));
}
return _list;
} // navBarItems
return SliverAppBar(
backgroundColor: Theme.of(context).primaryColor,
expandedHeight: _height,
pinned: true,
elevation: 0,
//TODO make actions appear only when SliverAppBar collapses
actions: _width > 800 ? _actions() : [],
flexibleSpace: FlexibleSpaceBar(
background: _background,
),
);
}
}
对于我在所有视图中使用的一般结构,这是我的 HomeView 的一个示例:
class HomeView extends StatelessWidget {
final double paddingHorizontal = 60;
final double paddingVertical = 60;
ScrollController _scrollController = ScrollController();
final _key = GlobalKey();
HomeView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
Widget navBarBackground() {
return Stack(...)
}
return Scaffold(
backgroundColor: Colors.white,
endDrawer: EndDrawer(),
body: CustomScrollView(
controller: _scrollController,
slivers: [
NavBar(navBarBackground()),
SliverList(
delegate: SliverChildListDelegate(
[
highlights(),
androidIosDesktop(),
multiplatform(),
catchPhrase(),
contact(),
const Footer(),
],
),
)
],
),
);
}
} //HomeView
这是显示的内容:
我希望它只显示这个:
是的。 但是,我想不是直接的。
您可以使用ScrollController
来实现此目的。 将一个ScrollController
附加到CustomScrollView
,然后观察该位置所在的控制器的offset
。 并基于它,您可以实现所需的输出。
我编写了一个简单的演示代码,这正是您需要的东西
试试 dartpad =>这里
我做了什么? (在试用 dartpad 之后看看)
ScrollController
添加到CustomScrollView
moreHeight
expandedHeight
高度offset
更改变量expandedHeight
。expandedHeight
我们将更改SliverAppBar
中的值编辑:
下面的代码是在分离作为无状态小部件的应用栏小部件之后,并从包含滚动视图的视图/页面传递参数并且可以使用滚动控制器(行为没有变化)
注意:以下代码可用于全高扩展应用栏
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: MyStatefulWidget(),
),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
late ScrollController _scrollController;
// variable height passed to SliverAppBar expanded height
double? _expandedHeight;
@override
initState() {
super.initState();
// initialize and add scroll listener
_scrollController = ScrollController();
_scrollController.addListener(_scrollListen);
// initially expanded height is full
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_expandedHeight = MediaQuery.of(context).size.height;
});
});
}
@override
dispose() {
// dispose the scroll listener and controller
_scrollController.removeListener(_scrollListen);
_scrollController.dispose();
super.dispose();
}
_scrollListen() {
final offset = _scrollController.offset;
final height = MediaQuery.of(context).size.height;
if (offset > height) {
// if offset is more height, disable expanded height
if (_expandedHeight != null) {
setState(() {
_expandedHeight = null;
});
}
} else {
// if offset is less, keep increasing the height to offset 0
setState(() {
_expandedHeight = height - offset;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
AppBarWidget(
expandedHeight: _expandedHeight,
),
SliverToBoxAdapter(
child: SizedBox(
height: 2000,
child: Center(
child: Container(
color: Colors.blue,
),
),
),
),
],
),
);
}
}
class AppBarWidget extends StatelessWidget {
const AppBarWidget({super.key, this.expandedHeight});
final double? expandedHeight;
// constant more height that is given to the expandedHeight
// of the SliverAppBar
// static double moreHeight = 200;
@override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
return SliverAppBar(
pinned: false,
floating: true,
expandedHeight: expandedHeight,
actions: [
TextButton(
onPressed: () {},
child: const Text('test'),
),
],
flexibleSpace: FlexibleSpaceBar(
// animate the opacity offset when expanded height is changed
background: AnimatedOpacity(
opacity: expandedHeight != null ? expandedHeight! / height : 0,
duration: const Duration(milliseconds: 300),
child: const FlutterLogo(),
),
),
);
}
}
编辑 2:我对您的代码进行了细微更改
正如我所见,您需要为背景展开全高,我已包含在上面的代码以及下面的代码中。
导航栏
class NavBar extends StatelessWidget {
const NavBar({this.background, this.expandedHeight});
final double? expandedHeight;
final Widget? background;
@override
SliverAppBar build(BuildContext context) {
double _width = MediaQuery.of(context).size.width;
double? _height = MediaQuery.of(context).size.height;
List<Widget> _actions() {
List<Widget> _list = [];
List _titles = Navigation(context).routes.keys.toList();
List _routes = Navigation(context).routes.values.toList();
_selectView(String route) {
Navigator.of(context).pushNamed(route);
}
Widget _singleItem(String text, String route) {
return InkWell(
onTap: () => _selectView(route),
borderRadius: BorderRadius.circular(15),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
alignment: Alignment.center,
child: Text(
text,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
);
}
for (int i = 0; i < Navigation(context).showingLinks; i++) {
_list.add(_singleItem(_titles[i], _routes[i]));
}
return _list;
} // navBarItems
return SliverAppBar(
backgroundColor: Theme.of(context).primaryColor,
expandedHeight: expandedHeight,
pinned: true,
elevation: 0,
//TODO make actions appear only when SliverAppBar collapses
actions: _width > 800 ? _actions() : [],
flexibleSpace: FlexibleSpaceBar(
// animate the opacity offset when expanded height is changed
background: AnimatedOpacity(
opacity: expandedHeight != null ? expandedHeight! / _height : 0,
duration: const Duration(milliseconds: 300),
child: background,
),
),
);
}
}
主页视图
class HomeView extends StatefulWidget {
const HomeView({Key? key}) : super(key: key);
@override
State<HomeView> createState() => _HomeView();
}
class _HomeView extends State<HomeView> {
final double paddingHorizontal = 60;
final double paddingVertical = 60;
late ScrollController _scrollController;
// variable height passed to SliverAppBar expanded height
double? _expandedHeight;
final _key = GlobalKey();
@override
initState() {
super.initState();
// initialize and add scroll listener
_scrollController = ScrollController();
_scrollController.addListener(_scrollListen);
// initially expanded height is full
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_expandedHeight = MediaQuery.of(context).size.height;
});
});
}
@override
dispose() {
// dispose the scroll listener and controller
_scrollController.removeListener(_scrollListen);
_scrollController.dispose();
super.dispose();
}
_scrollListen() {
final offset = _scrollController.offset;
final height = MediaQuery.of(context).size.height;
if (offset > height) {
// if offset is more height, disable expanded height
if (_expandedHeight != null) {
setState(() {
_expandedHeight = null;
});
}
} else {
// if offset is less, keep increasing the height to offset 0
setState(() {
_expandedHeight = height - offset;
});
}
}
@override
Widget build(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
Widget navBarBackground() {
return Stack(...)
}
return Scaffold(
backgroundColor: Colors.white,
endDrawer: EndDrawer(),
body: CustomScrollView(
controller: _scrollController,
slivers: [
NavBar(
background: navBarBackground(),
expandedHeight: _expandedHeight,
),
SliverList(
delegate: SliverChildListDelegate(
[
highlights(),
androidIosDesktop(),
multiplatform(),
catchPhrase(),
contact(),
const Footer(),
],
),
)
],
),
);
}
} //HomeView
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.