[英]Show (slide in) or hide (slide out) flutter AppBar on screen tap
請我嘗試創建這種效果,當點擊屏幕時 AppBar 滑出並在再次點擊時滑入。
通過將浮動和捕捉設置為 true,我可以在 SliverAppBar 中創建類似的東西。 不同之處在於 appBar 在向下滾動時顯示,在屏幕被點擊或向上滾動時隱藏。
這是 SliverAppBar 的示例代碼:
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
controller: _ctrlr,
slivers: <Widget>[
SliverAppBar(
floating: true,
snap: true,
),
SliverList(
delegate: SliverChildListDelegate([
Text('1', style: TextStyle(fontSize: 160.0),),
Text('2', style: TextStyle(fontSize: 160.0),),
Text('3', style: TextStyle(fontSize: 160.0),),
Text('4', style: TextStyle(fontSize: 160.0),),
]),
)
],
),
);
}
我怎樣才能做到這一點? 我還考慮將 AppBar 放在 Stack 中,但我認為這不是最好的方法。 對你的幫助表示感謝!
我遇到了類似的需求,並發現了您的問題。 由於沒有答案,我自己嘗試解決問題。 我知道你在 6 個月前問過這個問題,但我正在提供一個(幾乎完整的)答案,以防其他人遇到它。
(如果我的方法不夠優雅,我深表歉意,但在撰寫本文時,我只使用 Flutter 大約一個星期。:)
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';
class FramePage extends StatefulWidget {
final String title;
final String imageUrl;
FramePage({Key key, this.title, this.imageUrl}) : super(key: key);
@override
_FramePageState createState() => _FramePageState();
}
class _FramePageState extends State<FramePage> with SingleTickerProviderStateMixin {
AnimationController _controller;
bool _appBarVisible;
@override
void initState() {
super.initState();
_appBarVisible = true;
_controller = AnimationController(
duration: const Duration(milliseconds: 700),
value: 1.0,
vsync: this,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _toggleAppBarVisibility() {
_appBarVisible = !_appBarVisible;
_appBarVisible ? _controller.forward() : _controller.reverse();
}
Widget get _imageWidget {
return Center(
child: GestureDetector(
onTap: () => setState(() { _toggleAppBarVisibility(); } ),
child: Container(
foregroundDecoration: new BoxDecoration(color: Color.fromRGBO(155, 85, 250, 0.0)),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: widget.imageUrl,
fit: BoxFit.cover,
),
),
),
);
}
@override
Widget build(BuildContext context)
{
Animation<Offset> offsetAnimation = new Tween<Offset>(
begin: Offset(0.0, -70),
end: Offset(0.0, 0.0),
).animate(_controller);
return Scaffold(
body: Stack(
children: <Widget>[
_imageWidget,
SlideTransition(
position: offsetAnimation,
child: Container(
height: 75,
child: AppBar(
title: Text(widget.title),
),
),
),
],
)
);
}
}
本質上,AppBar 作為 Scaffold 的直接部分被移除,而是被添加到 Stack 中,在那里它實際上可以被動畫化。 為了確保圖像在其后面可見,它被放置在一個容器中,以便可以控制它的高度(否則,您將無法看到圖像)。
在我上面的代碼中,點擊圖像會使 AppBar 縮回,再次點擊會使它重新出現。 但是,出於某種原因,我實際上無法讓它平滑地前后動畫,但效果就在那里。
在實踐中,它看起來像這樣:
如果有人(在我做之前)弄清楚我錯過了什么以使其順利動畫,請隨時提供幫助。
只需將 Bob H. 解決方案中的 SlideTransition 替換為 AnimatedBuilder 和 Transform.translate 小部件:
animation: offsetAnimation,
builder: (context, child) {
return Transform.translate(
offset: offsetAnimation.value,
child: Container( ....```
這是我的回答:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool show = true;
@override
Widget build(BuildContext context) {
var appbar = AppBar();
var maxHeight = appbar.preferredSize.height;
return SafeArea(
child: Scaffold(
body: Stack(
children: <Widget>[
Positioned.fill(
child: GestureDetector(
onTap: () {
setState(() {
show = !show;
});
},
child: Container(
color: Colors.black,
child: Center(child: FlutterLogo())))),
AnimatedAlign(
duration: kThemeAnimationDuration,
alignment: Alignment(0, show ? -1 : -2),
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: maxHeight),
child: FlexibleSpaceBar.createSettings(
currentExtent: maxHeight,
child: appbar,
),
),
),
],
),
),
);
}
}
我在這里遇到了CopsOnRoad建議的更好方法: Flutter - 如何在頁面上動態顯示或隱藏應用欄
只是重新分享給其他人。
我們可以在另一個小部件中抽象動畫部分,例如:
class SlidingAppBar extends PreferredSize {
SlidingAppBar({
@required this.child,
@required this.controller,
@required this.visible,
});
@override
final PreferredSizeWidget child;
@override
Size get preferredSize => child.preferredSize;
final AnimationController controller;
final bool visible;
@override
Widget build(BuildContext context) {
visible ? controller.reverse() : controller.forward();
return SlideTransition(
position: Tween<Offset>(begin: Offset.zero, end: Offset(0, -1)).animate(
CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn),
),
child: child,
);
}
}
現在這個SlidingAppBar
小部件可以與Scaffold
的appBar
字段一起使用,而不是使用Stack
小部件,例如:
class _MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
bool _visible = true;
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// extendBodyBehindAppBar: !_visible, // Uses entire screen after hiding AppBar
appBar: SlidingAppBar(
controller: _controller,
visible: _visible,
child: AppBar(title: Text('AppBar')),
),
body: GestureDetector(
onTap: () => setState(() => _visible = !_visible),
child: Container(
height: double.infinity,
child: Text('App content...'),
)
)
);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.