نوار ابزار متحرک یا Collapsing Toolbar در فلاتر (Flutter)

سلام به همه . چند وقتی هست با فلاتر اشنا شدم و سعی دارم توی این فریم ورک بهتر بشم و هدفم این هست با توجه به کم بودن منابع فارسی ، توی این مسیر به هر مشکلی که برخوردم راه حلشو به اشتراک بزارم.خوب اگر توسعه دهنده اندروید باشید میدونید که طراحی لایه های واکنش پذیر نسبت به اسکرول کار خیلی اسونیه و به راحتی میشه با استفاده از لیوت هایی که اونجا موجود هست انجامش داد ولی توی فلتر طراحی چنین چیزی یه مقداری پیچیده تره (برعکس تمام چیزاش که به نسبت راحت تره ?).نتیجه کاری که من انجام میدم این میشهبه طور کامل لایه اصلی توی فلتر برای چنین کاری NestedScrollView هست و تمام لایه ها برای واکنش پذیر نسبت به اسکرول باید درون همین طراحی بشن .این ویجت یک SliverAppBar دریافت میکنه و اون لایه میانی بین Toolbar و Tabbar یعنی دقیقا همون لایه واکنش پذیر توی همین قرار داده میشه var flexibleSpaceWidget = new SliverAppBar( expandedHeight: 200.0, pinned: true, flexibleSpace: FlexibleSpaceBar( centerTitle: true, title: Text(&quotDeveloper Libs&quot, style: TextStyle( color: Colors.white, fontSize: 16.0, )), background: Image.asset( &quotassets/logo.png&quot, )), actions: <Widget>[ new Padding( padding: EdgeInsets.all(5.0), child: _buildActions(), ), ], );همینجور که میبنید این Appbar یک اکشن دریافت میکنه این دقیقا همون دکمه دایره شکل (FAB ) هست که وقتی Tabbar به سمت بالا اسکرول میشه ظاهر میشهWidget _buildActions() { Widget profile = new GestureDetector( onTap: () => showProfile(), child: new Container( height: 30.0, width: 45.0, decoration: new BoxDecoration( shape: BoxShape.circle, color: Colors.grey, image: new DecorationImage( image: new ExactAssetImage(&quotassets/logo.png&quot), fit: BoxFit.cover, ), border: Border.all(color: Colors.black, width: 2.0), ), ), ); double scale; if (scrollController.hasClients) { scale = scrollController.offset / 300; scale = scale * 2; if (scale > 1) { scale = 1.0; } } else { scale = 0.0; } return new Transform( transform: new Matrix4.identity()..scale(scale, scale), alignment: Alignment.center, child: profile, ); }خوب حالا برای اینکه بتونیم tab رو هم به قسمت واکنش پذیرمون اظافه کنیم باید از پارامتر delegate در sliver header استفاده کنیم و کار تمومه .من تمام کد رو اینجا میزارم import 'package:flutter/material.dart'; import 'package:flutter_collapsing_toolbar/tab_screen.dart'; class CollapsingTab extends StatefulWidget { @override _CollapsingTabState createState() => new _CollapsingTabState(); } class _CollapsingTabState extends State<CollapsingTab> { ScrollController scrollController; Widget _buildActions() { Widget profile = new GestureDetector( onTap: () => showProfile(), child: new Container( height: 30.0, width: 45.0, decoration: new BoxDecoration( shape: BoxShape.circle, color: Colors.grey, image: new DecorationImage( image: new ExactAssetImage(&quotassets/logo.png&quot), fit: BoxFit.cover, ), border: Border.all(color: Colors.black, width: 2.0), ), ), ); double scale; if (scrollController.hasClients) { scale = scrollController.offset / 300; scale = scale * 2; if (scale > 1) { scale = 1.0; } } else { scale = 0.0; } return new Transform( transform: new Matrix4.identity()..scale(scale, scale), alignment: Alignment.center, child: profile, ); } @override void dispose() { scrollController.dispose(); super.dispose(); } @override void initState() { super.initState(); scrollController = new ScrollController(); scrollController.addListener(() => setState(() {})); } @override Widget build(BuildContext context) { var flexibleSpaceWidget = new SliverAppBar( expandedHeight: 200.0, pinned: true, flexibleSpace: FlexibleSpaceBar( centerTitle: true, title: Text(&quotDeveloper Libs&quot, style: TextStyle( color: Colors.white, fontSize: 16.0, )), background: Image.asset( &quotassets/logo.png&quot, )), actions: <Widget>[ new Padding( padding: EdgeInsets.all(5.0), child: _buildActions(), ), ], ); return Scaffold( body: new DefaultTabController( length: 3, child: NestedScrollView( controller: scrollController, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return <Widget>[ flexibleSpaceWidget, SliverPersistentHeader( delegate: _SliverAppBarDelegate( TabBar( labelColor: Colors.black87, unselectedLabelColor: Colors.black26, tabs: [ Tab( icon: Icon(Icons.account_box), text: &quotDetail&quot, ), Tab(icon: Icon(Icons.add_location), text: &quotAddress&quot), Tab(icon: Icon(Icons.monetization_on), text: &quotEarning&quot), ], ), ), pinned: true, ), ]; }, body: new TabBarView( children: <Widget>[ new TabScreen(&quotDetail&quot), new TabScreen(&quotAddress&quot), new TabScreen(&quotEarning&quot), ], ), ), ), ); } showProfile() { Navigator.pushNamed(context, '/profile'); } } class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { final TabBar _tabBar; _SliverAppBarDelegate(this._tabBar); @override double get minExtent => _tabBar.preferredSize.height; @override double get maxExtent => _tabBar.preferredSize.height; @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return new Container( child: _tabBar, ); } @override bool shouldRebuild(_SliverAppBarDelegate oldDelegate) { return false; } }خوب امیدوارم کارتون راه افتاده باشه :) بدرودمن چیزهای زیاد از فلاتر توی کانالم میزارم میتونید من رو از اونجا دنبال کنید.کانال من