Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Customized Modal sheet
import 'dart:async';
import 'package:flutter/material.dart';
/// Below is the usage for this function, you'll only have to import this file
/// [radius] takes a double and will be the radius to the rounded corners of this modal
/// [color] will color the modal itself, the default being `Colors.white`
/// [builder] takes the content of the modal, if you're using [Column]
/// or a similar widget, remember to set `mainAxisSize: MainAxisSize.min`
/// so it will only take the needed space.
///
/// ```dart
/// showRoundedModalBottomSheet(
/// context: context,
/// radius: 10.0, // This is the default
/// color: Colors.white, // Also default
/// builder: (context) => ???,
/// );
/// ```
Future<T> showRoundedModalBottomSheet<T>({
@required BuildContext context,
@required WidgetBuilder builder,
Color color = Colors.white,
double radius = 10.0,
}) {
assert(context != null);
assert(builder != null);
assert(radius != null && radius > 0.0);
assert(color != null && color != Colors.transparent);
return Navigator.push<T>(
context,
_RoundedCornerModalRoute<T>(
builder: builder,
color: color,
radius: radius,
barrierLabel:
MaterialLocalizations.of(context).modalBarrierDismissLabel,
));
}
class _RoundedModalBottomSheetLayout extends SingleChildLayoutDelegate {
_RoundedModalBottomSheetLayout(this.progress);
final double progress;
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return new BoxConstraints(
minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth,
minHeight: 0.0,
maxHeight: constraints.maxHeight * 9.0 / 10.0);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
return new Offset(0.0, size.height - childSize.height * progress);
}
@override
bool shouldRelayout(_RoundedModalBottomSheetLayout oldDelegate) {
return progress != oldDelegate.progress;
}
}
class _RoundedCornerModalRoute<T> extends PopupRoute<T> {
_RoundedCornerModalRoute({
this.builder,
this.barrierLabel,
this.color,
this.radius,
RouteSettings settings,
}) : super(settings: settings);
final WidgetBuilder builder;
final double radius;
final Color color;
@override
Color get barrierColor => Colors.black54;
@override
bool get barrierDismissible => true;
@override
String barrierLabel;
AnimationController _animationController;
@override
AnimationController createAnimationController() {
assert(_animationController == null);
_animationController =
BottomSheet.createAnimationController(navigator.overlay);
return _animationController;
}
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return MediaQuery.removePadding(
context: context,
removeTop: true,
child: Theme(
data: Theme.of(context).copyWith(canvasColor: Colors.transparent),
child: AnimatedBuilder(
animation: animation,
builder: (context, child) => CustomSingleChildLayout(
delegate: _RoundedModalBottomSheetLayout(animation.value),
child: BottomSheet(
animationController: _animationController,
onClosing: () => Navigator.pop(context),
builder: (context) => Container(
decoration: BoxDecoration(
color: this.color,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(this.radius),
topRight: Radius.circular(this.radius),
),
),
child: SafeArea(child: Builder(builder: this.builder)),
),
),
),
),
),
);
}
@override
bool get maintainState => false;
@override
bool get opaque => false;
@override
Duration get transitionDuration => Duration(milliseconds: 200);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.