0

I need to design screen like this in short videovideo_link

I did this but its not very similar to the previous effect

here I create CustomScrollView with NotificationListener to achieve snap effect, but is still begging and isused TransitionAppBar to make appbar and used SliverPersistentHeader which implements SliverPersistentHeaderDelegate to control on align size and position

 import 'dart:math';
 import 'dart:developer' as d;
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
 
 class FinalScroll extends StatefulWidget {
   FinalScroll({Key? key}) : super(key: key);
 
   @override
   State<FinalScroll> createState() => _FinalScrollState();
 }
 
 class _FinalScrollState extends State<FinalScroll> {
   final ScrollController _controller = ScrollController();
 
   final double kLength = 300;
 
   final double kLengthSnap = 225;
 
   final Duration kDurationSnap = const Duration(milliseconds: 20);
 
   @override
   Widget build(BuildContext context) {
     if (!(!_controller.hasClients || _controller.offset == 0)) {
       // print('controll offset ${_controller.offset}');
 
     }
     double sizeImage = kLength;
     return SafeArea(
       child: Scaffold(
         body: LayoutBuilder(builder: (context, s) {
           return NotificationListener(
             onNotification: (scrollEndNotification) {
               // print('controll offset ${_controller.offset}');
 
               if (scrollEndNotification is ScrollEndNotification) {
                 if (_controller.offset < 0.4 * kLength) {
                   print('snap from CTB');
 
                   Future.microtask(
                     () {
                       return _controller.animateTo(0.0,
                           duration: kDurationSnap, curve: Curves.bounceInOut);
                     },
                   );
                   setState(() {
                     sizeImage = kLength;
                   });
                 }
                 if (_controller.offset > kLength * 0.4 &&
                     _controller.offset <= kLength * .6) {
                   print('snap from CTT');
 
                   Future.microtask(() => _controller.animateTo(kLength * 0.6,
                       duration: kDurationSnap, curve: Curves.bounceInOut));
                   setState(() {
                     sizeImage = 50;
                   });
                 }
               }
 
               return false;
             },
             child: CustomScrollView(
               controller: _controller,
               physics: const BouncingScrollPhysics(),
               slivers: <Widget>[
                 TransitionAppBar(
                   extent: kLength,
                   sizeImage: sizeImage,
                   avatar: const Text("Rancho"),
                   title: const Text(''),
                 ),
                 SliverList(
                   delegate: SliverChildBuilderDelegate(
                     (context, index) {
                       return ListTile(
                         title: Text("${index}a"),
                       );
                     },
                     childCount: 25,
                   ),
                 )
               ],
             ),
           );
         }),
       ),
     );
   }
 }
 
 class TransitionAppBar extends StatefulWidget {
   final Widget avatar;
   final Widget title;
   final double extent;
   final double sizeImage;
 
   const TransitionAppBar({
     required this.avatar,
     required this.title,
     this.extent = 250,
     required this.sizeImage,
     Key? key,
   }) : super(key: key);
 
   @override
   State<TransitionAppBar> createState() => _TransitionAppBarState();
 }
 
 class _TransitionAppBarState extends State<TransitionAppBar>
     with TickerProviderStateMixin {
   @override
   Widget build(BuildContext context) {
     return MediaQuery.removePadding(
       context: context,
       removeBottom: true,
       child: SliverPersistentHeader(
         pinned: true,
         floating: true,
         delegate: _TransitionAppBarDelegate(
             avatar: widget.avatar,
             sizeImage: widget.sizeImage,
             title: widget.title,
             extent: widget.extent > 200 ? widget.extent : 200,
             vsync: this),
       ),
     );
   }
 }
 
 class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
   _TransitionAppBarDelegate(
       {required this.avatar,
       required this.title,
       required this.sizeImage,
       this.extent = 250,
       required this.vsync});
 
   final double sizeImage;
 
   final Widget avatar;
   final Widget title;
   final double extent;
 
   ///   ===================  init  ========= ////
   final _avatarMarginTween =
       EdgeInsetsTween(begin: EdgeInsets.zero, end: const EdgeInsets.all(16));
 
   ///from BTC
   final _titleMarginTweenBTC = EdgeInsetsTween(
       begin: EdgeInsets.zero, end: const EdgeInsets.only(left: 70));
   final _titleAlignTweenBTC = AlignmentTween(
       begin: const Alignment(-.7, .8), end: const Alignment(-1.0, 0.2));
   final _avatarAlignTweenBTC =
       AlignmentTween(begin: const Alignment(-1, 1), end: Alignment.centerLeft);
 
   ///from CTT
   final _titleMarginTweenCTT = EdgeInsetsTween(
       begin: const EdgeInsets.only(left: 70), end: EdgeInsets.zero);
   final _titleAlignTweenCTT = AlignmentTween(
       begin: const Alignment(-1.0, 0.2), end: const Alignment(-.2, 0));
   final _avatarAlignTweenCTT = AlignmentTween(
       begin: Alignment.centerLeft, end: const Alignment(-.7, 0.0));
 
   final decorationTween = DecorationTween(
       begin: const BoxDecoration(
           shape: BoxShape.rectangle,
           color: Colors.red,
           image: DecorationImage(
               fit: BoxFit.cover,
               alignment: Alignment.centerLeft,
               image: AssetImage('asset/dash.jpeg'))),
       end: const BoxDecoration(
         shape: BoxShape.circle,
         color: Colors.yellow,
         image: DecorationImage(
           alignment: Alignment.centerLeft,
           fit: BoxFit.fill,
           image: AssetImage(
             'asset/dash.jpeg',
           ),
         ),
       ));
 
   @override
   Widget build(
       BuildContext context, double shrinkOffset, bool overlapsContent) {
     final double topPadding = MediaQuery.of(context).padding.top;
 
     final double visibleMainHeight = maxExtent - shrinkOffset - topPadding;
     final double extraToolbarHeight =
         max(minExtent - extent - topPadding - (kToolbarHeight), 0.0);
     final double visibleToolbarHeight =
         visibleMainHeight - extent - extraToolbarHeight;
 
     final bool isScrolledUnder =
         overlapsContent || (shrinkOffset > maxExtent - minExtent);
     final double toolbarOpacity =
         (visibleToolbarHeight / (kToolbarHeight)).clamp(0.0, 1.0);
 
     final progress = min(1.0, shrinkOffset / maxExtent);
     //margin
     final avatarMargin = _avatarMarginTween.lerp(progress);
     final titleMarginBTC = _titleMarginTweenBTC.lerp(progress);
     final titleMarginCTT = _titleMarginTweenCTT.lerp(shrinkOffset / 300);
     //align
     final avatarAlignBTC = _avatarAlignTweenBTC.lerp(progress);
     final titleAlignBTC = _titleAlignTweenBTC.lerp(progress);
     final avatarAlignCTT = _avatarAlignTweenCTT.lerp(shrinkOffset / extent);
     final titleAlignCTT = _titleAlignTweenCTT.lerp(shrinkOffset / extent);
     //decoration
     final decorationT = decorationTween.lerp(progress);
     // print(
     //     'shrinkOffset:$shrinkOffset maxExtent: $maxExtent   minExtent:  $minExtent  progress : $progress');
 print(sizeImage);
     final Widget toolbar = Stack(
       fit: StackFit.passthrough,
       children: <Widget>[
         AnimatedContainer(
           duration: const Duration(milliseconds: 100),
           height: minExtent,
           constraints: BoxConstraints(maxHeight: minExtent),
           color: Colors.grey.shade100,
         ),
         LayoutBuilder(builder: (context, constraint) {
           var checkIfProgressThanFromValue = progress < 0.3;
           var checkLessThan1 = !(progress > 0.01);
           return SizedBox(
             height: sizeImage,
             width: sizeImage==maxExtent?MediaQuery.of(context).size.width:30,
             child: Row(
               mainAxisSize: MainAxisSize.max,
               mainAxisAlignment: MainAxisAlignment.start,
               crossAxisAlignment: CrossAxisAlignment.stretch,
               children: [
                 Flexible(
                   child: Padding(
                     padding: avatarMargin,
                     child: AnimatedContainer(
                       duration: const Duration(milliseconds: 100),
                       constraints: BoxConstraints(
                           maxHeight: maxExtent,
                           maxWidth: constraint.maxWidth,
                           minHeight: 0,
                           minWidth: 0),
                       height: checkLessThan1 ? maxExtent : 50,
                       width: checkLessThan1
                           ? MediaQuery.of(context).size.width
                           : 30,
                       // decoration: decorationT,
                       child: OverflowBox(
                         maxWidth: MediaQuery.of(context).size.width,
                         child: SizedBox(
                           height: sizeImage,
                           width: checkLessThan1
                               ? MediaQuery.of(context).size.width
                               : 30,
                           child: FittedBox(
                             fit: BoxFit.fitHeight,
                             alignment: shrinkOffset > minExtent
                                 ? avatarAlignCTT
                                 : avatarAlignBTC,
                             child: ClipRRect(
                               borderRadius: checkLessThan1
                                   ? BorderRadius.zero
                                   : BorderRadius.circular(
                                       min(24, progress * 24)),
                               clipBehavior: Clip.antiAlias,
                               child: AnimatedSize(
                                 duration: Duration(milliseconds: 100),
                                 child: Image.asset(
                                   'asset/dash.jpeg',
 
                                   // alignment: shrinkOffset > minExtent
                                   //     ? avatarAlignCTT
                                   //     : avatarAlignBTC,
                                   fit: BoxFit.fill,
                                   height: sizeImage,
                                   width: sizeImage == maxExtent
                                       ? MediaQuery.of(context).size.width
                                       : 30,
                                   // height: checkIfProgressThanFromValue
                                   //     ? maxExtent
                                   //     : 50,
                                   // width: checkIfProgressThanFromValue
                                   //     ? MediaQuery.of(context).size.width
                                   //     : 50,
                                 ),
                               ),
                             ),
                           ),
                         ),
                       ),
                     ),
                   ),
                 ),
               ],
             ),
           );
         }),
         _RenderTilte(
             progress: progress,
             titleMarginBTC: titleMarginBTC,
             titleMarginCTT: titleMarginCTT,
             titleAlignBTC: titleAlignBTC,
             titleAlignCTT: titleAlignCTT)
       ],
     );
 
     final Widget appBar = FlexibleSpaceBar.createSettings(
       minExtent: minExtent,
       maxExtent: maxExtent,
       currentExtent: max(minExtent, maxExtent - shrinkOffset),
       child: toolbar,
     );
     return SafeArea(
       child: LayoutBuilder(builder: (context, c) {
         return SizedBox(
             height: c.maxHeight,
             width: c.maxWidth,
             child: ClipRect(child: appBar));
       }),
     );
   }
 
   @override
   double get maxExtent => extent;
 
   @override
   double get minExtent => max(kToolbarHeight, (maxExtent * .33));
 
   @override
   bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
     return true;
   }
 
   @override
   OverScrollHeaderStretchConfiguration get stretchConfiguration =>
       OverScrollHeaderStretchConfiguration(
           stretchTriggerOffset: 150, onStretchTrigger: () async {});
 
   @override
   FloatingHeaderSnapConfiguration? get snapConfiguration =>
       FloatingHeaderSnapConfiguration(
           curve: Curves.bounceInOut,
           duration: const Duration(milliseconds: 10));
 
   @override
   PersistentHeaderShowOnScreenConfiguration? get showOnScreenConfiguration =>
       const PersistentHeaderShowOnScreenConfiguration();
 
   @override
   final TickerProvider vsync;
 }
 
 class _RenderTilte extends StatelessWidget {
   const _RenderTilte({
     Key? key,
     required this.progress,
     required this.titleMarginBTC,
     required this.titleMarginCTT,
     required this.titleAlignBTC,
     required this.titleAlignCTT,
   }) : super(key: key);
 
   final double progress;
   final EdgeInsets titleMarginBTC;
   final EdgeInsets titleMarginCTT;
   final Alignment titleAlignBTC;
   final Alignment titleAlignCTT;
 
   @override
   Widget build(BuildContext context) {
     return Padding(
       padding: progress < 0.3 ? titleMarginBTC : titleMarginCTT,
       child: Align(
         alignment: progress < 0.3 ? titleAlignBTC : titleAlignCTT,
         child: Opacity(
           opacity: progress == 0 || progress == 1 ? 1 : progress * 0.01,
           child: const Text(
             'abd alazeez ',
           ),
         ),
       ),
     );
   }
 }
 

here how to build the previous design and I don't know what the next step

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Abd Alazeez
  • 126
  • 1
  • 5
  • Try Sliverscroll or any sliver – Arbiter Chil Jul 24 '22 at 06:15
  • Does [this](https://stackoverflow.com/questions/73092277/flutter-collapsible-appbar-with-custom-layout-and-animation/73093528#73093528) answer your question? It'd need some adjustments but the logic is there. – lepsch Jul 24 '22 at 06:19
  • @lepsch this is not similar .is very simple i need to make that without using FlexibleSpaceBar it isn't given full control on my widget – Abd Alazeez Jul 24 '22 at 08:38

0 Answers0