//A simple container with a SingleChildScrollView. The trick is to set the child of SingleChildScrollView height //exceed the height of parent scroll widget so it can be scrolled. The BouncingScrollPhysics helps the scroll retain its //original position if it doesn't cross the threshold to play reveal animation. //This widget is added by _getInitScreenWidgets() method Positioned( right: 0, left: 0, bottom: 0, child: Container( height: widget.height * .5, child: SingleChildScrollView( controller: _scrollController, physics: BouncingScrollPhysics(), child: Container( height: widget.height * .5 + .1, // color:Colors.yellow, ), ), ), ),
//Intercepts the bounce animation and start dragg animation void _handleSwipe() { _swipeUpBounceAnimationController.stop(canceled: true); double dy = _scrollController.position.pixels;
//If user scroll 70% of the scrolling region we proceed towards reveal animation if (scrollRatio > .7) _playRevealAnimation(); else setState(() { _swipeUpDy = dy * -1; }); }
//Update scene state to "reveal" and start corresponding animation //This method is called when drag excced our defined threshold void _playRevealAnimation() { setState(() { currentScreenState = CURRENT_SCREEN_STATE.REVEALING_ANIMATING_STATE; _revealAnimationController.forward(); _amoebaAnimationController.forward(); }); }
//Animation controller for expanding the curve animation _revealAnimationController = AnimationController(duration: Duration(milliseconds: 500), vsync: this) ..addStatusListener((status) { if (status == AnimationStatus.completed) setState(() { currentScreenState = CURRENT_SCREEN_STATE.POST_REVEAL_STATE; _postRevealAnimationController.forward(); }); });
//Tween for animating height of the curve during reveal process _swipeArcAnimation = Tween<double>(begin: _initialCurveHeight, end: _finalCurveHeight) .animate(CurvedAnimation( parent: _revealAnimationController, curve: Curves.easeInCubic));
//Animation for the mid control point of cubic bezier curve to show acceleration effect in response to user drag. _swipeArchHeightAnimation = TweenSequence<double>( <TweenSequenceItem<double>>[ TweenSequenceItem<double>( tween: Tween<double>(begin: 0, end: 200), weight: 50.0, ), TweenSequenceItem<double>( tween: Tween<double>(begin: 200, end: 0), weight: 50.0, ), ], ).animate(CurvedAnimation( parent: _revealAnimationController, curve: Curves.easeInCubic));
//Animation controller for showing animation after reveal _postRevealAnimationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this);
//Scale animation for showing center logo after reveal is completed _centerIconScale = Tween<double>(begin: 0, end: .5).animate(CurvedAnimation( parent: _postRevealAnimationController, curve: Curves.fastOutSlowIn, ));
//_centerIconScale animation used by FAB in the middle Positioned.fromRelativeRect( rect: _titleBaseLinePosTranslateAnim.value.shift(Offset(0, 18)), child: ScaleTransition( scale: _centerIconScale, child: FloatingActionButton( backgroundColor: Colors.white, elevation: 5, onPressed: null, child: Icon(Icons.monetization_on_outlined, size: 100, color: isLeftTabSelected ? Colors.deepPurple : Colors.pinkAccent))), ),
///The background for selected tab. On the basis of tab selected, the foreground container is translated away, ///revealing the underlying background container. If the screen state is just set to reveal, then in the ///initial state no foreground container is added which is signified by _tabSelectionAnimation set to null. ///_tabSelectionAnimation is only set when either of the tab is pressed. List<Widget> _getBgWidgets() { List<Widget> widgets = []; Color foreGroundColor; Color backgroundColor; if (isLeftTabSelected) { foreGroundColor = Colors.deepPurple; backgroundColor = Colors.pink; } else { foreGroundColor = Colors.pink; backgroundColor = Colors.deepPurple; }