Bottom Layout In Flutter
Screenshot 1 :

Screenshot 2 :

1. main.dart
import 'package:flutter/material.dart'; import 'stopper.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Hello")), body: Builder( builder: (context) { final h = MediaQuery.of(context).size.height; return Center( child: MaterialButton( color: Colors.green, child: Text("Show Stopper"), onPressed: () { showStopper( context: context, stops: [0.4 * h, h], builder: (context, scrollController, scrollPhysics, stop) { return ClipRRect( borderRadius: stop == 0 ? BorderRadius.only( topLeft: Radius.circular(10), topRight: Radius.circular(10), ): BorderRadius.only(), clipBehavior: Clip.antiAlias, child: Container( color: Colors.orange, child: CustomScrollView( slivers: <Widget>[ SliverAppBar( title: Text("What's Up?"), backgroundColor: Colors.orange, automaticallyImplyLeading: false, primary: false, floating: true, pinned: true, ), SliverList( delegate: SliverChildBuilderDelegate( (context, idx) => ListTile( title: Text("Nothing much"), subtitle: Text("$idx"), ), childCount: 100, ), ) ], controller: scrollController, physics: scrollPhysics, ), ), ); }, ); }, ) ); }, ), ); } }
2. Stopper.dart
library stopper; import 'package:flutter/material.dart'; import 'dart:math'; /// A builder function to be passed to [Stopper]. typedef Widget StopperBuilder( /// A build context BuildContext context, /// A scroll controller to be passed to a scrollable widget ScrollController controller, // A scroll physics to be passed to a scrollable widget ScrollPhysics physics, /// The current stop value. int stop ); /// A widget that changes its height to one of the predefined values based on user-initiated dragging. /// Designed to be used with [showBottomSheet()] method. class Stopper extends StatefulWidget { /// The list of stop heights in logical pixels. The values must be sorted from lowest to highest. final List<double> stops; /// This callback function is called when the user triggers a close. If null, the bottom sheet cannot be closed by the user. final Function onClose; /// A builder to build the contents of the bottom sheet. final StopperBuilder builder; /// The initial stop. final int initialStop; /// The minimum offset (in logical pixels) necessary to trigger a stop change when dragging. final double dragThreshold; /// The constructor. Stopper({ Key key, @required this.builder, @required this.stops, this.initialStop = 0, this.onClose, this.dragThreshold = 25 }) : assert(initialStop < stops.length), super(key: key); @override StopperState createState() => StopperState(); } /// The state of [Stopper] widget. class StopperState extends State<Stopper> with SingleTickerProviderStateMixin { List<double> _stops; int _currentStop; int _targetStop; bool _dragging = false; bool _closing = false; double _dragOffset; double _closingHeight; ScrollController _scrollController; ScrollPhysics _scrollPhysics; Animation<double> _animation; AnimationController _animationController; Tween<double> _tween; ScrollPhysics _getScrollPhysicsForStop(s) { if (s == _stops.length - 1) return BouncingScrollPhysics(); else return NeverScrollableScrollPhysics(); } @override void initState() { super.initState(); this._stops = widget.stops; this._currentStop = widget.initialStop; this._targetStop = _currentStop; _scrollController = ScrollController(); _scrollPhysics = _getScrollPhysicsForStop(_currentStop); _animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 500)); final curveAnimation = CurvedAnimation(parent: _animationController, curve: Curves.linear); _tween = Tween<double>(begin: _stops[_currentStop], end: _stops[_targetStop]); _animation = _tween.animate(curveAnimation); _scrollController.addListener(() { if (_scrollController.offset < -widget.dragThreshold) { if (this._currentStop != this._targetStop || _dragging) return; if (this._currentStop > 0) { final h0 = height; this._targetStop = this._currentStop - 1; _animate(h0, _stops[_targetStop]); } else if (!_closing) { close(); } } }); } @override void didUpdateWidget(Stopper oldWidget) { super.didUpdateWidget(oldWidget); this._stops = widget.stops; this._currentStop = min(_currentStop, _stops.length - 1); this._targetStop = min(_currentStop, _stops.length - 1); } @override void dispose() { super.dispose(); _animationController.dispose(); _scrollController.dispose(); } /// The current stop value. The value changes after the stop change animation is complete. get stop => _currentStop; set stop(nextStop) { _targetStop = max(0, min(_stops.length - 1, nextStop)); _animate(height, nextStop); } /// Returns true if this [Stopper] can be closed by the user. bool get canClose { return widget.onClose != null; } /// Closes the bottom sheet. Repeated calls to this method will be ignored. void close() { if (!_closing && canClose) { _closingHeight = height; _animationController.stop(canceled: true); _dragging = false; _closing = true; widget.onClose(); } } void _animate(double from, double to, [double velocity]) { _tween.begin = from; _tween.end = to; _animationController.value = 0; if (_scrollController.offset < 0) _scrollController.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.linear); _animationController.fling().then((_) { this._currentStop = this._targetStop; setState(() { _scrollPhysics = _getScrollPhysicsForStop(_currentStop); }); }); } /// The current height of the bottom sheet. get height { if (_closing) return _closingHeight; else if (_dragging) return _stops[_currentStop] + _dragOffset; else if (_animationController.isAnimating) return _animation.value; else return _stops[_currentStop]; } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, child: GestureDetector( onVerticalDragStart: (details) { if (_currentStop != _targetStop) return; _scrollController.jumpTo(0); _dragging = true; _dragOffset = 0; setState(() {}); }, onVerticalDragUpdate: (details) { if (_dragging) { _scrollController.jumpTo(0); _dragOffset -= details.delta.dy; setState(() {}); } }, onVerticalDragEnd: (details) { if (!_dragging || _closing) return; if (_dragOffset > widget.dragThreshold) { _targetStop = min(_currentStop + 1, _stops.length - 1); } else if (_dragOffset < -widget.dragThreshold) { _targetStop = max(canClose ? -1 : 0, _currentStop - 1); } if (_targetStop < 0) { close(); } else { _dragging = false; _animate(_stops[_currentStop] + _dragOffset, _stops[_targetStop]); } }, child: widget.builder(context, _scrollController, _scrollPhysics, _currentStop), ), builder: (context, child) { return SizedBox( height: min(_stops[_stops.length - 1], max(0, height)), child: child, ); }); } } /// Shows the Stopper bottom sheet. /// Returns a [PersistentBottomSheetController] that can be used PersistentBottomSheetController showStopper( { /// The key of the [Stopper] widget Key key, /// The build context @required BuildContext context, /// The builder of the bottom sheet @required StopperBuilder builder, /// The list of stop heights as logical pixel values. Use [MediaQuery] to compute the heights relative to screen height. /// The order of the stop heights must be from the lowest to the highest. @required List<double> stops, /// The initial stop number. int initialStop = 0, /// If [true] then the user can close the bottom sheet dragging it down from the lowest stop. bool userCanClose = true, /// The minimum offset (in logical pixels) to trigger a stop change when dragging. double dragThreshold = 25 }) { PersistentBottomSheetController cont; cont = showBottomSheet( context: context, builder: (context) { return Stopper( key: key, builder: builder, stops: stops, initialStop: initialStop, dragThreshold: dragThreshold, onClose: userCanClose ? () { cont.close(); }: null, ); }, ); return cont; }
The flutter tutorial is a website that bring you the latest and amazing resources of code. All the languages codes are included in this website. The languages like flutter, android, java,kotlin etc.with the help of this languages any user can develop the beautiful application
For more information about Flutter. visit www.fluttertutorial.in