import 'package:after_layout/after_layout.dart'; import 'package:flutter/material.dart'; class HomePage extends StatelessWidget { const HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { double rpx = MediaQuery.of(context).size.width / 750; return Scaffold( body: Container( child: HomeMain( rpx: rpx, ), ), ); } } class HomeMain extends StatefulWidget { HomeMain({Key? key, required this.rpx}) : super(key: key); final double rpx; _HomeMainState createState() => _HomeMainState(); } class _HomeMainState extends State with TickerProviderStateMixin { double extraPicHeight = 0; late BoxFit fitType; double prevDy = 0; double rpx = 0; late AnimationController animationController; late Animation anim; late TabController tabController; double expanedHeight = 300; @override void initState() { super.initState(); tabController = TabController(vsync: this, length: 3); prevDy = 0; fitType = BoxFit.fitWidth; animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 300)); anim = Tween(begin: 0.0, end: 0.0).animate(animationController); } updatePicHeight(changed) { if (prevDy == 0) { prevDy = changed; } extraPicHeight += changed - prevDy; if (extraPicHeight >= 200 * widget.rpx) { fitType = BoxFit.fitHeight; } else { fitType = BoxFit.fitWidth; } setState(() { prevDy = changed; extraPicHeight = extraPicHeight; fitType = fitType; }); } updateExpandedHeight(height) { setState(() { expanedHeight = height; }); } runAnimate() { setState(() { anim = Tween(begin: extraPicHeight, end: 0.0).animate(animationController) ..addListener(() { if (extraPicHeight >= widget.rpx * 200) { fitType = BoxFit.fitHeight; } else { fitType = BoxFit.fitWidth; } setState(() { extraPicHeight = anim.value; fitType = fitType; }); }); prevDy = 0; }); } @override Widget build(BuildContext context) { double rpx = MediaQuery.of(context).size.width / 750; return Listener( onPointerMove: (result) { updatePicHeight(result.position.dy); }, onPointerUp: (_) { runAnimate(); animationController.forward(from: 0); }, child: CustomScrollView( physics: ClampingScrollPhysics(), slivers: [ SliverAppBar( pinned: true, floating: true, actions: [ IconButton( icon: Icon(Icons.search), onPressed: () {}, ), IconButton( icon: Icon(Icons.more_vert), onPressed: () {}, ), ], leading: IconButton( icon: Icon(Icons.arrow_back), onPressed: () {}, ), bottom: PreferredSize( preferredSize: Size.fromHeight(50), child: TabBar( controller: tabController, tabs: [ Text("作品 91"), Text("动态 91"), Text("喜欢 91"), ], )), // expandedHeight: 510 * rpx + extraPicHeight, expandedHeight: expanedHeight + extraPicHeight, flexibleSpace: Container( child: TopBarWithCallback( extraPicHeight: extraPicHeight, fitType: fitType, updateHeight: updateExpandedHeight, ), ), ), SliverList( delegate: SliverChildBuilderDelegate((context, index) { return Container( height: 30, alignment: Alignment.centerLeft, color: Colors.blueAccent, child: Text("This is itm $index"), margin: EdgeInsets.symmetric( horizontal: 20 * rpx, vertical: 10 * rpx), ); }, childCount: 80), ) ], )); } } class TopBarWithCallback extends StatefulWidget { TopBarWithCallback( {Key? key, required this.extraPicHeight, required this.fitType, required this.updateHeight}) : super(key: key); final double extraPicHeight; final BoxFit fitType; final Function(double) updateHeight; _TopBarWithCallbackState createState() => _TopBarWithCallbackState(); } class _TopBarWithCallbackState extends State with AfterLayoutMixin { @override Widget build(BuildContext context) { return Container( child: SliverTopBar( extraPicHeight: widget.extraPicHeight, fitType: widget.fitType, ), ); } @override void afterFirstLayout(BuildContext context) { RenderObject? box = context.findRenderObject(); // double height = // box.getMaxIntrinsicHeight(MediaQuery.of(context).size.width); // widget.updateHeight(height); } } class SliverTopBar extends StatelessWidget { const SliverTopBar( {Key? key, required this.extraPicHeight, required this.fitType}) : super(key: key); final double extraPicHeight; final BoxFit fitType; @override Widget build(BuildContext context) { double rpx = MediaQuery.of(context).size.width / 750; return Stack( children: [ Column( mainAxisSize: MainAxisSize.min, children: [ Image.asset( "assets/images/temple.jpg", width: 750 * rpx, height: 300 * rpx + extraPicHeight, fit: fitType, ), Container( padding: EdgeInsets.only(top: 20 * rpx), height: 120 * rpx, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Container( height: 80 * rpx, width: 330 * rpx, child: ElevatedButton( style: ButtonStyle( foregroundColor: MaterialStateProperty.all(Color(0xffdc3254)) ), child: Text( "+关注", style: TextStyle( fontSize: 30 * rpx, color: Colors.white, letterSpacing: 3 * rpx), ), onPressed: () {}, )), SizedBox( width: 10 * rpx, ), Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(2), color: Color(0xff3b3c49), ), height: 80 * rpx, child: IconButton( icon: Center( child: Icon( Icons.arrow_drop_down, color: Colors.white, size: 50 * rpx, )), onPressed: () {}, ), ), SizedBox( width: 30 * rpx, ) ], ), ), SizedBox( height: 100 * rpx, ), Container( width: 750 * rpx, padding: EdgeInsets.symmetric(horizontal: 30 * rpx), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "马友发", style: TextStyle( fontSize: 55 * rpx, color: Colors.white, fontWeight: FontWeight.bold), ), Text("抖音号:1234567", style: TextStyle( fontSize: 27 * rpx, color: Colors.white, )), SizedBox( height: 15 * rpx, ) ], )), Padding( padding: EdgeInsets.symmetric(horizontal: 20 * rpx), child: Divider( color: Colors.grey[700], ), ), Container( padding: EdgeInsets.symmetric(horizontal: 20 * rpx), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon( Icons.shop, color: Color(0xffeacd3f), ), Text( "商品橱窗", style: TextStyle(color: Color(0xffeacd3f)), ) ], ), Icon(Icons.keyboard_arrow_right, color: Color(0xffeacd3f)) ], )), Padding( padding: EdgeInsets.symmetric(horizontal: 20 * rpx), child: Divider( color: Colors.grey[700], ), ), Container( padding: EdgeInsets.symmetric(horizontal: 20 * rpx), height: 100 * rpx, width: 750 * rpx, child: Text( "爱神的箭发;黑色大力开发哈的\n阿萨德饭还是电话费拉开始的计划发", style: TextStyle(color: Colors.white, fontSize: 30 * rpx), ), ), Container( padding: EdgeInsets.symmetric( horizontal: 20 * rpx, vertical: 10 * rpx), child: Row( children: [ Tag( text: "深圳", ), Tag( text: "世界之窗", ), Tag( text: "深圳大学", ) ], ), ), Container( padding: EdgeInsets.symmetric( horizontal: 20 * rpx, vertical: 30 * rpx), child: Row( children: [ NumWithDesc( numm: "100.2w", desc: "获赞", ), NumWithDesc( numm: "15", desc: "关注", ), NumWithDesc( numm: "10.8w", desc: "粉丝", ), ], ), ) ], ), Positioned( top: 250 * rpx + extraPicHeight, left: 30 * rpx, child: Container( decoration: BoxDecoration( color: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(220 * rpx)), width: 220 * rpx, height: 220 * rpx, padding: EdgeInsets.all(10 * rpx), child: CircleAvatar( backgroundImage: NetworkImage( "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg"))), ) ], ); } } class Tag extends StatelessWidget { const Tag({Key? key, required this.text}) : super(key: key); final String text; @override Widget build(BuildContext context) { double rpx = MediaQuery.of(context).size.width / 750; return Container( child: Text( text, style: TextStyle(fontSize: 26 * rpx, color: Color(0xff64626e)), ), color: Color(0xff3b3c49), padding: EdgeInsets.all(10 * rpx), margin: EdgeInsets.only(right: 10 * rpx), ); } } class NumWithDesc extends StatelessWidget { const NumWithDesc({Key? key, required this.numm, required this.desc}) : super(key: key); final String numm; final String desc; @override Widget build(BuildContext context) { double rpx = MediaQuery.of(context).size.width / 750; double textSize = 35 * rpx; return Padding( padding: EdgeInsets.only(right: 20 * rpx), child: Row( children: [ Text( numm, style: TextStyle( fontSize: textSize, color: Colors.white, fontWeight: FontWeight.bold), ), SizedBox( width: 10 * rpx, ), Text(desc, style: TextStyle(fontSize: textSize, color: Color(0xff3b3c49))) ], )); } } // import 'package:flutter/material.dart'; // class SelfHomePage extends StatelessWidget { // const SelfHomePage({Key? key}) : super(key: key); // @override // Widget build(BuildContext context) { // return Scaffold( // body: CustomScrollView( // physics: ClampingScrollPhysics(), // slivers: [ // SliverAppBar( // leading: IconButton( // icon: Icon(Icons.arrow_back), // onPressed: () {}, // ), // floating: true, // pinned: false, // snap: true, // expandedHeight: 250, // flexibleSpace: FlexibleSpaceBar( // title: Text("This is Sliver App Bar"), // background: Image.asset("assets/images/temple.jpg",height: 250,fit: BoxFit.fitWidth,), // ), // ), // SliverList(delegate: SliverChildBuilderDelegate((context,index){ // return Container(child: Text("This is item $index",style: TextStyle(fontSize: 20),),color: Colors.redAccent,); // },)) // ], // ), // ); // } // }