Flutter: Long Press on picture to get zoomed preview like Instagram

后端 未结 2 1681
忘掉有多难
忘掉有多难 2021-01-16 11:48

so I am currently having a grid of pictures and I want to implement a feature from instagram: If you longPress on one of the pictures, you get a a larger version of that pic

相关标签:
2条回答
  • 2021-01-16 12:44

    You could use Peek and Pop https://pub.dev/packages/peek_and_pop

    Is an implementation for Flutter based on the iOS functionality of the same name.

    0 讨论(0)
  • 2021-01-16 12:46

    Here's the improved vewrsion that resembles the same exact UX as of Instagram with blurred background.

    We can achieve this using a combination of Stateful Widget, Stack and BackdropFliter, here is the sample code -

    import 'dart:ui';
    
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Counter Demo',
          theme: ThemeData.light(),
          home: Scaffold(
            appBar: AppBar(
              backgroundColor: Colors.blueGrey,
              centerTitle: true,
              title: Text("Demo App"),
            ),
            body: Stacked(),
          ),
        );
      }
    }
    
    class Stacked extends StatefulWidget {
      @override
      _StackedState createState() => _StackedState();
    }
    
    class _StackedState extends State<Stacked> {
      final List<String> images = [
        "1.jpg",
        "2.jpg",
        "3.jpg",
        "4.jpg",
        "5.jpg",
        "6.jpg",
        "7.jpg",
        "8.jpg",
        "9.jpg",
        "10.jpg",
      ];
    
      bool _showPreview = false;
      String _image = "assets/images/1.jpg";
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
            child: Stack(
          children: [
            GridView.builder(
              itemCount: images.length,
              gridDelegate:
                  SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
              itemBuilder: (BuildContext context, int index) {
                return GestureDetector(
                  onLongPress: () {
                    setState(() {
                      _showPreview = true;
                      _image = "assets/images/${images[index]}";
                    });
                  },
                  onLongPressEnd: (details) {
                    setState(() {
                      _showPreview = false;
                    });
                  },
                  child: Padding(
                    padding: const EdgeInsets.all(4.0),
                    child: Card(
                      elevation: 4,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(5.0),
                      ),
                      clipBehavior: Clip.hardEdge,
                      child: Image.asset("assets/images/${images[index]}"),
                    ),
                  ),
                );
              },
            ),
            if (_showPreview) ...[
              BackdropFilter(
                filter: ImageFilter.blur(
                  sigmaX: 5.0,
                  sigmaY: 5.0,
                ),
                child: Container(
                  color: Colors.white.withOpacity(0.6),
                ),
              ),
              Container(
                child: Center(
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(10.0),
                    child: Image.asset(
                      _image,
                      height: 300,
                      width: 300,
                    ),
                  ),
                ),
              ),
            ],
          ],
        ));
      }
    }
    

    This is just a baseline example and there are endless possibilities you can modify this to achieve behavior you want.


    Another simple way is we can build this by using StatefulWidget and IndexedStack -

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Counter Demo',
          theme: ThemeData.light(),
          home: Scaffold(
            appBar: AppBar(
              backgroundColor: Colors.blueGrey,
              centerTitle: true,
              title: Text("Demo App"),
            ),
            body: Body(),
          ),
        );
      }
    }
    
    class Body extends StatefulWidget {
      @override
      _BodyState createState() => _BodyState();
    }
    
    class _BodyState extends State<Body> {
      final List<String> images = [
        "1.jpg",
        "2.jpg",
        "3.jpg",
        "4.jpg",
        "5.jpg",
        "6.jpg",
        "7.jpg",
        "8.jpg",
        "9.jpg",
        "10.jpg",
      ];
    
      int _index = 0;
      String _image = "assets/images/1.jpg";
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: IndexedStack(
            index: _index,
            children: [
              GridView.builder(
                itemCount: images.length,
                gridDelegate:
                    SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
                itemBuilder: (BuildContext context, int index) {
                  return GestureDetector(
                    onLongPress: () {
                      setState(() {
                        _index = 1;
                        _image = "assets/images/${images[index]}";
                      });
                    },
                    onLongPressEnd: (details) {
                      setState(() {
                        _index = 0;
                      });
                    },
                    child: Padding(
                      padding: const EdgeInsets.all(4.0),
                      child: Card(
                        elevation: 4,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(5.0),
                        ),
                        clipBehavior: Clip.hardEdge,
                        child: Image.asset("assets/images/${images[index]}"),
                      ),
                    ),
                  );
                },
              ),
              Container(
                decoration: BoxDecoration(
                  color: Colors.white.withOpacity(0.2),
                ),
                child: Center(
                  child: ConstrainedBox(
                    constraints: BoxConstraints(
                      maxHeight: 400,
                      maxWidth: 400,
                    ),
                    child: Image.asset(
                      _image,
                    ),
                  ),
                ),
              )
            ],
          ),
        );
      }
    }
    

    You can check output for above code here.

    0 讨论(0)
提交回复
热议问题