I'm creating a responsive MaterialPageRoute and I need some support

46 views Asked by At

I'm creating a responsive MaterialPageRoute, that combines the current MaterialPageRoute for small screens, and a dialog for big screens. Basically I want to create a new type of route that accepts a parameter called breakingWidth, and changes it's behavior based on that width.

  • On mobile devices it will behave like the current MaterialPageRoute with it's correspondent animation for iOS and Android
  • On tablet and desktop it will behave like a showDialog, with a Dialog on the middle of the screen

I have copied some code of the current implementation of the MaterialPageRoute, and done some changes to adapt it to the behavior that I want.

This is the code that I currently have. I have removed big comment blocks and imports to make the code block smaller.

class ResponsiveMaterialPageRoute<T> extends PageRoute<T> with MaterialRouteTransitionMixin<T> {
  /// Construct a MaterialPageRoute whose contents are defined by [builder].
  ResponsiveMaterialPageRoute({
    required this.breakingWidth,
    required this.builder,
    this.maintainState = true,
  });

  final WidgetBuilder builder;

  @override
  final double breakingWidth;

  @override
  final bool opaque = false;

  @override
  Widget buildContent(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    if (width > breakingWidth) {
      return Dialog(
        child: ClipRRect(
          borderRadius: BorderRadius.circular(28),
          child: builder(context)
        ),
      );
    }
    else {
      return builder(context);
    }
  }

  @override
  final bool maintainState;

  @override
  String get debugLabel => '${super.debugLabel}(${settings.name})';
}


mixin MaterialRouteTransitionMixin<T> on PageRoute<T> {
  /// Builds the primary contents of the route.
  @protected
  Widget buildContent(BuildContext context);

  @override
  Duration get transitionDuration => const Duration(milliseconds: 300);

  @override
  Color? get barrierColor => null;

  @override
  String? get barrierLabel => null;

  late final double breakingWidth;

  @override
  bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {
    // Don't perform outgoing animation if the next route is a fullscreen dialog.
    return (nextRoute is MaterialRouteTransitionMixin && !nextRoute.fullscreenDialog)
      || (nextRoute is CupertinoRouteTransitionMixin && !nextRoute.fullscreenDialog);
  }

  @override
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) {
    final Widget result = buildContent(context);
    return Semantics(
      scopesRoute: true,
      explicitChildNodes: true,
      child: result,
    );
  }

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
    if (MediaQuery.of(context).size.width > breakingWidth) {
      return FadeTransition(
        opacity: CurvedAnimation(
          parent: animation,
          curve: Curves.easeOut,
        ),
        child: child,
      );
    }
    else {
      final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme;
      return theme.buildTransitions<T>(this, context, animation, secondaryAnimation, child);
    }
  }
}

Here you have an example of the current behavior. The only thing that's remaining to do is to add the translucent overlay behind the route, but I don't know how to do it. Hopefully someone can help me. example

0

There are 0 answers