Flutter page widget that is dismissed by swipe gestures, with Hero style animations, Inspired by Facebook and Instagram stories.

Overview

dismissible_page

🔥 🚀
Creates page that is dismissed by swipe gestures, with Hero style animations, Inspired by FB, IG stories.

Live Demo

Contents

Support

First thing first give it a star

Discord Channel

Contribute

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Overview

Creates page that is dismissed by swipe gestures, with Hero style animations, Inspired by FB, IG stories.

Installation

1. Depend on it

Add this to your package's pubspec.yaml file:

dependencies:  
  dismissible_page: ^0.5.5  

2. Install it

You can install packages from the command line:

with pub:

$ pub get  

with Flutter:

$ flutter packages get  

3. Import it

Now in your Dart code, you can use:

import 'package:dismissible_page/dismissible_page.dart';  

Properties

  DismissiblePage({  
 required this.child, this.isFullScreen = true, this.disabled = false, this.backgroundColor = Colors.black, this.direction = DismissDirection.vertical, this.dismissThresholds = const <DismissDirection, double>{},  
    this.dragStartBehavior = DragStartBehavior.start,  
    this.crossAxisEndOffset = 0.0,  
    this.dragSensitivity = 0.7,  
    this.minRadius = 7,  
    this.minScale = .85,  
    this.maxRadius = 30,  
    this.maxTransformValue = .4,  
    this.startingOpacity = 1,  
    this.onDismiss,  
    this.onDragStart,  
    this.onDragEnd,  
    this.reverseDuration = const Duration(milliseconds: 500),  
    Key? key,  
  }) : super(key: key);  

Example

Import the package:

import 'package:dismissible_page/dismissible_page.dart';  
import 'package:example/_models.dart';  
import 'package:flutter/material.dart';  
import 'package:flutter/widgets.dart';  
  
void main() => runApp(AppView());  
  
class AppView extends StatelessWidget {  
  @override  
  Widget build(BuildContext context) => MaterialApp(home: AppHome());  
}  
  
class AppHome extends StatefulWidget {  
  @override  
  _AppHomeState createState() => _AppHomeState();  
}  
  
class _AppHomeState extends State<AppHome> {  
  final stories = [  
    StoryModel(title: 'STORY'),  
    StoryModel(title: 'STORY'),  
    StoryModel(title: 'STORY'),  
    StoryModel(title: 'STORY'),  
    StoryModel(title: 'STORY'),  
    StoryModel(title: 'STORY'),  
  ];  
  
  @override  
  Widget build(BuildContext context) {  
    final padding = MediaQuery.of(context).padding;  
    return Scaffold(  
      body: SingleChildScrollView(  
        padding: padding,  
        child: Column(  
          children: [  
            Padding(  
              padding: const EdgeInsets.all(20),  
              child: Text('Dismissible', style: TextStyle(fontSize: 24)),  
            ),  
            SizedBox(  
              height: 120,  
              child: ListView.separated(  
                padding: EdgeInsets.symmetric(horizontal: 20),  
                scrollDirection: Axis.horizontal,  
                itemBuilder: (_, int i) => StoryWidget(story: stories[i]),  
                separatorBuilder: (_, int i) => SizedBox(width: 10),  
                itemCount: stories.length,  
              ),  
            ),  
          ],  
        ),  
      ),  
    );  
  }  
}  
  
  
class StoryWidget extends StatelessWidget {  
  final StoryModel story;  
  
  const StoryWidget({this.story});  
  
  @override  
  Widget build(BuildContext context) {  
    return GestureDetector(  
      onTap: () {  
        context.pushTransparentRoute(StoryPage(story: story));  
      },  
      child: Hero(  
        tag: story.storyId,  
        child: Container(  
          height: 120,  
          width: 88,  
          padding: const EdgeInsets.all(8),  
          child: Text(  
            story.title,  
            style: Theme.of(context)  
                .textTheme  
                .button  
                .copyWith(color: Colors.white),  
          ),  
          clipBehavior: Clip.antiAlias,  
          alignment: Alignment.bottomLeft,  
          decoration: BoxDecoration(  
            borderRadius: BorderRadius.circular(12),  
            image: DecorationImage(  
              fit: BoxFit.cover,  
              image: NetworkImage(story.imageUrl),  
            ),  
          ),  
        ),  
      ),  
    );  
  }  
}  
  
  
class StoryPage extends StatelessWidget {  
  final StoryModel story;  
  const StoryPage({this.story});  
  
  @override  
  Widget build(BuildContext context) {  
    return DismissiblePage(  
      onDismiss: () => Navigator.of(context).pop(),  
      isFullScreen: false,  
      dragSensitivity: .4,  
      maxTransformValue: 4,  
      direction: DismissDirection.vertical,  
      child: Material(  
        color: Colors.transparent,  
        child: Hero(  
          tag: story.storyId,  
          child: Container(  
            padding: const EdgeInsets.all(20),  
            child: Text(  
              story.title,  
              style: Theme.of(context)  
                  .textTheme  
                  .button  
                  .copyWith(color: Colors.white),  
            ),  
            clipBehavior: Clip.antiAlias,  
            alignment: Alignment.bottomLeft,  
            decoration: BoxDecoration(  
              image: DecorationImage(  
                fit: BoxFit.cover,  
                image: NetworkImage(story.imageUrl),  
              ),  
            ),  
          ),  
        ),  
      ),  
    );  
  }  
}  
  
class StoryModel {  
  final storyId = UniqueKey();  
  final String title;  
  String imageUrl;  
  
  String get nextVehicleUrl =>  
      'https://source.unsplash.com/collection/1989985/${Random().nextInt(20) + 400}x${Random().nextInt(20) + 800}';  
  
  StoryModel({this.title, this.imageUrl}) {  
    imageUrl = nextVehicleUrl;  
  }  
}  
Comments
  • Add callback to report on drag progress

    Add callback to report on drag progress

    We're trying to fade out the page background (which is separate from the DismissiblePage widget) when the user starts dragging, but unfortunately there's no way to get the drag progress.

    It would be nice if the drag progress could be reported via a callback, ideally with a value of 0.0-1.0, indicating how much the dismissible has been dragged compared to its total width/height.

    opened by cachapa 6
  • When `backgroundColor` is set as `Colors.transparent`, transition has grey/black color

    When `backgroundColor` is set as `Colors.transparent`, transition has grey/black color

    I think this happens from the fact that Colors.transparent.withOpacity(value) creates a grey shade even if the base color is transparent.

    Both in Single and Multi axis transitions we need to add a condition for backgroundColor being Colors.transparent and do not add withOpacity in those cases

    https://github.com/Tkko/Flutter_dismissible_page/blob/c8ddb543e3c3280641b045e5fea08c8848f210a0/lib/src/multi_axis_dismissible_page.dart#L171 https://github.com/Tkko/Flutter_dismissible_page/blob/c8ddb543e3c3280641b045e5fea08c8848f210a0/lib/src/single_axis_dismissible_page.dart#L269

    opened by aytunch 5
  • Not work with InteractiveViewer

    Not work with InteractiveViewer

    Hi ! Thanks for this package it's really nice to have !

    I got a problem when I try to add in the child a InteractiveViewer to be able to zoom into the widget (an image). The dismiss interaction not work anymore.

    Simple example to show the problem:

    class ImageZoomPage extends HookConsumerWidget {
      const ImageZoomPage({super.key});
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        const imageUrl =
            'https://thumbs.dreamstime.com/b/url-text-displayed-touch-screen-modern-tablet-hands-holding-white-mobile-device-66853601.jpg';
        return DismissiblePage(
          onDismissed: () {
            context.router.pop();
          },
          direction: DismissiblePageDismissDirection.multi,
          child: Hero(
            tag: 'image',
            child: InteractiveViewer( // <-- Here the InteractiveViewer broke the DismissiblePage
              minScale: 0.1,
              maxScale: 3.0,
              clipBehavior: Clip.none,
              child: CachedNetworkImage(
                fit: BoxFit.fitWidth,
                cacheKey: imageUrl,
                imageUrl: imageUrl,
              ),
            ),
          ),
        );
      }
    }
    

    I have missing something ?

    opened by Kiruel 3
  • Added missing

    Added missing "disabled" implementation

    Hi, the new multi direction dismiss is a great addition and I immediately updated my app to use it. Unfortunately my code relied on the "disabled" parameter and that implementation was missing. I'm not sure if this is the best way to do it, but it worked for my use case. Thanks for this project 👍

    opened by Andre-lbc 2
  • Avoid publishing gif media assets to pub.dev

    Avoid publishing gif media assets to pub.dev

    Config files or media assets not relevant for the package functioning itself should be included in .pubignore to avoid unnecessary files get published and reduce package size.

    example/media/* should be included in .pubignore

    opened by luis901101 2
  • Is it possible to make drag animation faster?

    Is it possible to make drag animation faster?

    I would like to be able to make drag animation a bit faster, meaning it actually follows my finger when dragging, just like in telegram. Is it possible? If you could give me any pointers where i should look, i could change the code myself, because i need it asap. Thanks for your help.

    opened by andriiDesu 2
  • Background color is black when enabled and transparent when disabled

    Background color is black when enabled and transparent when disabled

    I'm trying to use this to build an image viewer similar to twitter. So I put an InteractiveViewer() inside of it.

    class MyImageViewer extends StatefulWidget {
      MyImageViewer({Key? key, required this.image}) : super(key: key);
      String image;
    
      @override
      _MyImageViewerState createState() => _MyImageViewerState();
    }
    
    class _MyImageViewerState extends State<MyImageViewer> {
    
    
      @override
      Widget build(BuildContext context) {
    
    
        return DismissiblePage(
            onDismiss: () => Navigator.of(context).pop(),
            isFullScreen: true,
            child:
            InteractiveViewer(
              child:
              Container(
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  image:
                  DecorationImage(
                    image:
                    CachedNetworkImageProvider(widget.image),
                    fit: BoxFit.contain,
                  ),
                ),
              ),
            )
        );
    
    
      }
    }
    

    Now it looks great and dismisses wonderfully.

    The problem is that if you zoom on the image and then naturally try to pan the image it will also dismiss the image as is expected behavior.

    So I've tried to build a system that will set the disabled flag anytime the image is zoom as follows:

    class _MyImageViewerState extends State<MyImageViewer> {
    
      final _transformationController = TransformationController();
      bool _dismissDisabled = false;
    
      void _onInteractionEnd(ScaleEndDetails details) {
        setState(() {});
      }
    
      void _onInteractionUpdate(ScaleUpdateDetails details) {
        debugPrint(details.scale.toString());
        if (details.scale > 1)
          {
            _dismissDisabled = true;
    
          }
        else
          {
            _dismissDisabled = false;
          }
      }
    
      @override
      Widget build(BuildContext context) {
    
    
        return DismissiblePage(
            backgroundColor: Colors.black,
            onDismiss: () => Navigator.of(context).pop(),
            isFullScreen: false,
            disabled: _dismissDisabled,
            child:
            GestureDetector(
              child: InteractiveViewer(
                onInteractionEnd: _onInteractionEnd,
                onInteractionUpdate: _onInteractionUpdate,
                transformationController: _transformationController,
                panEnabled: true,
                scaleEnabled: true,
                child:
                Container(
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    image:
                    DecorationImage(
                      image:
                      CachedNetworkImageProvider(widget.image),
                      fit: BoxFit.contain,
                    ),
                  ),
                ),
              ),
            )
        );
    
    
      }
    }
    

    When I do this however, the screen has a black background, which then goes to transparent when the disabled flag is set using the setState()

    is this a bug or am I doing this wrong?

    opened by mark8044 1
  • Feature/scrollable dismissible

    Feature/scrollable dismissible

    You can test the behavior by depending on the feature_branch or on the demo website (on the mobile or in the desktop with developers options opened)

    Depending on the ScrollPhysics the behavior is different and I'm not sure what to do about that | Android (ClampingScrollPhysics) | iOS (BouncingScrollPhysics) | |-|-| |

    opened by Tkko 0
  • Not working with CustomScrollView

    Not working with CustomScrollView

    Doesn't work when on top of a page that has a CustomScrollView and some slivers inside (SliverList) etc. Only dismisses sideways. If there is no scrollable content in CustomScrollView then works also in vertical. Any tips on how to approach view structure or is it a bug?

    enhancement 
    opened by czaku 13
  • Fade out page while dismissing

    Fade out page while dismissing

    I think currently the dissmissing page only scales down and moves. Also the previous page color changes. But instead it would be nicer to fade out the top page and see the bottom page the more we dismiss the page

    enhancement 
    opened by aytunch 1
Releases(0.6.1)
camilo velandia 69 Dec 30, 2022
Facebook based-app - A Facebook based app which actually looks like Facebook

Facebook based mobile application This project is a mobile application which act

Munem Sarker 3 Nov 23, 2022
Facebook-redesign - An app developed that show a Facebook inspired UI design

Superbe Lecteur de Musique fait avec Flutter ! Captures d'Écran Construire depui

Youssef Marzouk 4 Jul 7, 2022
Sardor Makhmudov 0 Feb 7, 2022
Stories like in Instagram, each story can include multiple images and videos. Package supports video, titles, preliminary caching.

flutter_instagram_stories A Flutter package for displaying stories just like Whatsapp & Instagram. Built-in groups (multiple stories with one icon), c

Alex Awaik 125 Dec 9, 2022
A simple way to share Instagram stories as an embedded feature within the Flutter application

Loopi Share A simple way to share Instagram stories as an embedded feature within the Flutter application. Introduction Words on both platforms Androi

Loopi 5 Sep 24, 2022
I created a welcome page, login page and signup page using Flutter

welcome_page UI design for welcome page, signUp page & Login page by Joy Obor Getting Started This project is a starting point for a Flutter applicati

spyder 0 Dec 29, 2021
A flutter plugin to get facebook deep links and log app events using the latest Facebook SDK to include support for iOS 14

Facebook Sdk For Flutter LinkedIn GitHub facebook_sdk_flutter allows you to fetch deep links, deferred deep links and log facebook app events. This wa

Saad Farhan 23 Dec 17, 2022
A widget that shows an image which can be scaled and dragged using gestures.

[DISCONTINUED] - 24.05.2021 While this widget was useful in the early days of Flutter, the Flutter team introduced an own way to zoom and pan, see Int

EPNW 15 May 3, 2022
An Instagram like text editor Flutter widget that helps you to change your text style.

TextEditor An instagram like text editor widget for flutter Show some ❤️ and star the repo to support the project Features Edit TextStyle object font

Mehdi Zarepour 68 Dec 16, 2022
Advanced & beautiful animations inspired by animate_do and Animate.css, every animation is a widget that contains default but customizable values 💙

animate_it An animation package inspired by animate_do and Animate.css. Since the original animate_do is not being maintained, I have decided to creat

Luke Moody 3 Oct 1, 2022
Creating complete social media app like instagram, facebook using flutter dart.

instoo The social media application that allows user to check out new feed, like, comment and even check other user’s profile. It has search, follow,

Pratul Pant 9 Dec 1, 2022
Instagram-clone - Instagram clone built using flutter and Firebase

Instagram-clone statistics of Firebase usage User Authentication for Instagram l

null 5 Jul 18, 2022
Neumorphic style - Example app with Flutter that displays a neumorphic style container

Flutter Neumorphic Style Example App Example app with Flutter that displays a ne

Piyush Nagpal 2 Mar 24, 2022
Easy to use, reliable and lightweight gesture detector for Flutter apps, exposing simple API for basic gestures

Simple Gesture Detector Easy to use, reliable and lightweight gesture detector for Flutter apps. Exposes simple API to react to basic gestures. Featur

Aleksander Woźniak 26 Nov 4, 2022
FLUTTER API: It's powerful navigation by gestures and taps. You can scroll from left to right or tap on the navigation icons.

scroll_navigation My other APIs Video Viewer Video Editor Helpers Features Fancy animations. Customizable colors. Works with the back button. Scrollin

Luis Felipe Murguia Ramos 14 Jun 14, 2022
Create bulk instagram quotes posts with custom background, style, font, size. built using flutter

Mini Canva minicanva.com Bulk Image Generator from given list of quotes, lines ?? Purpose Etsy is an E-commerce platform where we can sell digital goo

Ashish Pipaliya 7 Oct 29, 2022
Flutter app to browse Reddit with swiping gestures

Diaporama (for Reddit) A pretty simple Flutter app to browse Reddit with swiping gestures You select your content source (list of subreddits) and you

Simon 22 Nov 23, 2021
A flutter UI package provides a cell widget that has leading and trailing swipe action menu.

Language: English |中文简体 flutter_swipe_action_cell A package that can give you a cell that can be swiped ,effect is like iOS native If you like this pa

WenJingRui 261 Jan 7, 2023