Search code examples
dartflutterflutter-layout

Show fullscreen image onTap in Flutter


I have image shown using one of Flutter widgets

Image.network(....);

I want to add functionality that after tapping on image I can present this image in fullscreen mode. How it can be done?


Solution

  • You say you want something like in this flutter cookbook?

    import 'package:flutter/material.dart';
    
    void main() => runApp(HeroApp());
    
    class HeroApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Image/Detail Demo',
          home: MainScreen(),
        );
      }
    }
    
    class MainScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Main Screen'),
          ),
          body: GestureDetector(
            child: Hero(
              tag: 'imageHero',
              child: Image.network(
                'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
              ),
            ),
            onTap: () {
              Navigator.push(context, MaterialPageRoute(builder: (_) {
                return DetailScreen();
              }));
            },
          ),
        );
      }
    }
    
    class DetailScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: GestureDetector(
            child: Center(
              child: Hero(
                tag: 'imageHero',
                child: Image.network(
                  'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
                ),
              ),
            ),
            onTap: () {
              Navigator.pop(context);
            },
          ),
        );
      }
    }
    

    You can use the cache_network_image package to show the cached image without download it again.

    import 'package:flutter/material.dart';
    import 'package:cached_network_image/cached_network_image.dart';
    
    void main() => runApp(HeroApp());
    
    class HeroApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Image/Detail Demo',
          home: MainScreen(),
        );
      }
    }
    
    class MainScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Main Screen'),
          ),
          body: GestureDetector(
            child: Hero(
              tag: 'imageHero',
              child: CachedNetworkImage(
                imageUrl:  'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
                placeholder: new CircularProgressIndicator(),
                errorWidget: new Icon(Icons.error),
              )
            ),
            onTap: () {
              Navigator.push(context, MaterialPageRoute(builder: (_) {
                return DetailScreen();
              }));
            },
          ),
        );
      }
    }
    
    class DetailScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: GestureDetector(
            child: Center(
              child: Hero(
                tag: 'imageHero',
                child: CachedNetworkImage(
                  imageUrl:  'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
                  placeholder: new CircularProgressIndicator(),
                  errorWidget: new Icon(Icons.error),
                ),
              ),
            ),
            onTap: () {
              Navigator.pop(context);
            },
          ),
        );
      }
    }
    

    My final release (with real fullscreen):

    import 'package:flutter/material.dart';
    import 'package:cached_network_image/cached_network_image.dart';
    import 'package:flutter/services.dart';
    
    void main() => runApp(HeroApp());
    
    class HeroApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Image/Detail Demo',
          home: MainScreen(),
        );
      }
    }
    
    class MainScreen extends StatefulWidget {
      @override
      _MainScreenState createState() => _MainScreenState();
    }
    
    class _MainScreenState extends State<MainScreen> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Main Screen'),
          ),
          body: GestureDetector(
            child: Hero(
                tag: 'imageHero',
                child: CachedNetworkImage(
                  imageUrl:
                      'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
                  placeholder: new CircularProgressIndicator(),
                  errorWidget: new Icon(Icons.error),
                )),
            onTap: () {
              Navigator.push(context, MaterialPageRoute(builder: (_) {
                return DetailScreen();
              }));
            },
          ),
        );
      }
    }
    
    class DetailScreen extends StatefulWidget {
      @override
      _DetailScreenState createState() => _DetailScreenState();
    }
    
    class _DetailScreenState extends State<DetailScreen> {
      @override
      initState() {
        SystemChrome.setEnabledSystemUIOverlays([]);
        super.initState();
      }
    
      @override
      void dispose() {
        //SystemChrome.restoreSystemUIOverlays();
        SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: GestureDetector(
            child: Center(
              child: Hero(
                tag: 'imageHero',
                child: CachedNetworkImage(
                  imageUrl:
                      'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
                  placeholder: new CircularProgressIndicator(),
                  errorWidget: new Icon(Icons.error),
                ),
              ),
            ),
            onTap: () {
              Navigator.pop(context);
            },
          ),
        );
      }
    }
    

    Passing data from main to detail page

    Just to complete my answer, I add some code showing how you could pass the image url from main to detail page.

    import 'package:flutter/material.dart';
    import 'package:cached_network_image/cached_network_image.dart';
    import 'package:flutter/services.dart';
    
    void main() => runApp(HeroApp());
    
    class HeroApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Image/Detail Demo',
          home: MainScreen(),
        );
      }
    }
    
    class MainScreen extends StatefulWidget {
      @override
      _MainScreenState createState() => _MainScreenState();
    }
    
    class _MainScreenState extends State<MainScreen> {
      var _url = [
        'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
        'https://github.com/flutter/plugins/raw/master/packages/video_player/doc/demo_ipod.gif?raw=true'
      ];
      var _tag = ['imageHero', 'imageHero2'];
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Main Screen'),
          ),
          body: ListView(
            children: <Widget>[
              GestureDetector(
                child: Hero(
                    tag: _tag[0],
                    child: CachedNetworkImage(
                      imageUrl: _url[0],
                      placeholder: Center(child: Container(width: 32, height: 32,child: new CircularProgressIndicator())),
                      errorWidget: new Icon(Icons.error),
                    )),
                onTap: () {
                  Navigator.push(context, MaterialPageRoute(builder: (_) {
                    return DetailScreen(tag: _tag[0], url: _url[0]);
                  }));
                },
              ),
              GestureDetector(
                child: Hero(
                    tag: _tag[1],
                    child: CachedNetworkImage(
                      imageUrl: _url[1],
                      placeholder: Center(child: Container(width: 32, height: 32,child: new CircularProgressIndicator())),
                      errorWidget: new Icon(Icons.error),
                    )),
                onTap: () {
                  Navigator.push(context, MaterialPageRoute(builder: (_) {
                    return DetailScreen(tag: _tag[1], url: _url[1]);
                  }));
                },
              ),
            ],
          ),
        );
      }
    }
    
    class DetailScreen extends StatefulWidget {
      final String tag;
      final String url;
    
      DetailScreen({Key key, @required this.tag, @required this.url})
          : assert(tag != null),
            assert(url != null),
            super(key: key);
    
      @override
      _DetailScreenState createState() => _DetailScreenState();
    }
    
    class _DetailScreenState extends State<DetailScreen> {
      @override
      initState() {
        SystemChrome.setEnabledSystemUIOverlays([]);
        super.initState();
      }
    
      @override
      void dispose() {
        //SystemChrome.restoreSystemUIOverlays();
        SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: GestureDetector(
            child: Center(
              child: Hero(
                tag: widget.tag,
                child: CachedNetworkImage(
                  imageUrl: widget.url,
                  placeholder: Center(child: Container(width: 32, height: 32,child: new CircularProgressIndicator())),
                  errorWidget: new Icon(Icons.error),
                ),
              ),
            ),
            onTap: () {
              Navigator.pop(context);
            },
          ),
        );
      }
    }
    

    UPDATE

    In order to pop back tapping outside the image, bring outside the GestureDetector in the Detail widget.

    class _DetailScreenState extends State<DetailScreen> {
      @override
      initState() {
        SystemChrome.setEnabledSystemUIOverlays([]);
        super.initState();
      }
    
      @override
      void dispose() {
        //SystemChrome.restoreSystemUIOverlays();
        SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          child: Scaffold (
            body: Center(
              child: Hero(
                tag: widget.tag,
                child: CachedNetworkImage(
                  imageUrl: widget.url,
                  placeholder: Center(child: Container(width: 32, height: 32,child: new CircularProgressIndicator())),
                  errorWidget: new Icon(Icons.error),
                ),
              ),
            ),
          ),
          onTap: () {
            Navigator.pop(context);
          },
        );
      }
    }