我当时在Spotify上听音乐,然后开始想知道如何获得“艺术家”页面上显示的确切动画。
它包括条状导航,但也包括艺术家图像上方的文本(也许可以使用一个简单的堆栈) 还有一个浮动动作小部件(随机播放),最喜欢的是,向上滚动时,艺术家图像ZOOMS会返回! 我想在Flutter上重新创建它。
有人可以帮助我吗?
答案 0 :(得分:1)
我不使用Spotify。 但我希望它能给一个好的开始。
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
themeMode: ThemeMode.dark,
darkTheme: ThemeData.dark(),
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
double _appTopBarHeight = 60;
String artistName = 'Dennis Lloyd';
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverPersistentHeader(
delegate: MyDelegate(),
floating: true,
pinned: true,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(_, index) => Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(index.toString()),
SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title'),
Text('Subtitle'),
],
),
),
SizedBox(width: 10),
Icon(
Icons.more_vert,
color: Colors.white,
),
],
),
),
),
childCount: 100,
),
),
],
);
}
}
class MyDelegate extends SliverPersistentHeaderDelegate {
@override
Widget build(_, double shrinkOffset, bool overlapsContent) {
var shrinkPercentage =
min(1, shrinkOffset / (maxExtent - minExtent)).toDouble();
return Stack(
overflow: Overflow.clip,
fit: StackFit.expand,
children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
height: _appTopBarHeight,
color: Colors.black,
),
),
Column(
children: [
Flexible(
flex: 1,
child: Stack(
children: [
Container(
color: Colors.black,
),
Opacity(
opacity: 1 - shrinkPercentage,
child: Container(
height: 900,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitWidth,
alignment: FractionalOffset.topCenter,
image: NetworkImage(
'https://66.media.tumblr.com/c063f0b98040e8ec4b07547263b8aa15/tumblr_inline_ppignaTjX21s9on4d_540.jpg'),
)),
),
),
],
),
),
Container(
height: 50,
)
],
),
Stack(
overflow: Overflow.clip,
fit: StackFit.expand,
children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: Column(
children: [
Container(
height: _appTopBarHeight,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
Icons.arrow_back,
color: Colors.white,
),
Flexible(
child: Opacity(
opacity: shrinkPercentage,
child: Text(
artistName,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
),
Icon(
Icons.more_vert,
color: Colors.white,
),
],
),
),
),
Opacity(
opacity: max(1 - shrinkPercentage * 6, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(height: 200),
Text(
artistName,
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
),
),
Text(
'Subtitle',
style: TextStyle(color: Colors.white),
),
],
),
)
],
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Center(
child: RaisedButton(
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(),
),
onPressed: () {},
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 30, vertical: 5),
child: Text(
'SHUFFLE PLAY',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
),
),
),
)
],
),
],
);
}
@override
double get maxExtent => 400;
@override
double get minExtent => 110;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}