dbilgin / swipe_image_gallery

A scrollable, dismissable by swiping, zoomable gallery for Flutter, on which you can add a dynamic overlay.
MIT License
31 stars 16 forks source link

How do i achieve hero animations with GridTiles? #5

Closed Roxin92 closed 2 years ago

Roxin92 commented 2 years ago

Tried this but no luck:

class FirstPage extends StatefulWidget {
  var wallpaperList = <Wallpaper>[];

  @override
  _FirstPageState createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {

  StreamController<Widget> overlayController =
  StreamController<Widget>.broadcast();

  @override
  void dispose() {
    overlayController.close();
    super.dispose();
  }

  Query<Map<String, dynamic>> firstWallieQuery = FirebaseFirestore.instance
      .collection('Wallies')
      .orderBy('timestamp', descending: false)
      .limit(20);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _buildContents(),
    );
  }

  Widget _buildContents() {
    //THIS CODE IS USED TO RETRIEVE DATA FROM DB
    return FutureBuilder(
      future: firstWallieQuery.get(),
      builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasData) {
            print('DATA IS THERE ROXIN');
            var favWallManger =
                Provider.of<FavWallpaperManger>(context, listen: false);

            snapshot.data.docs.forEach((documentSnapshot) {
              var wallpaper = Wallpaper.fromDocumentSnapshot(documentSnapshot);

              if (favWallManger.isFavourite(wallpaper)) {
                wallpaper.isFavourite = true;
              }
              //THIS IS WHERE IM ADDING THE IMAGES TO A LIST AFTER RETRIEVING THEM FROM A DB
              widget.wallpaperList.add(wallpaper);
              print('ListHome: ${wallpaper.id}');
            });
          }
          print('GridRebuildHome');
          return GridView.builder(
            itemCount: widget.wallpaperList.length,
            itemBuilder: (BuildContext context, int indexx) {
              return InkResponse(
                //WHY I PUT SWIPE IMAGE GALLERY IN A STANDALONE METHOD IS BECAUSE IT WAS GETTING LONG AND MESSY
                onTap: () => swipeImageGallery(context, indexx).show(),
                child: GridTile(child: imageCache(indexx)),
              );
            },
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 3,
              childAspectRatio: 0.8,
            ),
          );
        } else {
          return Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    );
  }

  SwipeImageGallery swipeImageGallery(BuildContext context, int indexx) {
    return SwipeImageGallery(
      context: context,
      initialIndex: indexx,
      hideStatusBar: true,
      transitionDuration: 600,
      //heroProperties: heroProperties,
      itemBuilder: (context, index) {
        return Image(
            image: CachedNetworkImageProvider(
                widget.wallpaperList.elementAt(index).url));
      },
      itemCount: widget.wallpaperList.length,
      onSwipe: (index) {
        overlayController.add(FullScreenOverlayButtons(
          wallpaperList: widget.wallpaperList,
          initialPage: index,
          currentIndex: index,
          fromHome: true,
        ));
      },
      initialOverlay: FullScreenOverlayButtons(
        wallpaperList: widget.wallpaperList,
        initialPage: indexx,
        currentIndex: indexx,
        fromHome: true,
      ),
      overlayController: overlayController,
    );
  }

  Widget imageCache(int indexx) {
    return CachedNetworkImage(
      imageUrl: widget.wallpaperList.elementAt(indexx).url,
      fit: BoxFit.cover,
    );
  }
}
dbilgin commented 2 years ago

Hi @Roxin92 thank you for opening an issue! I am a bit confused about a couple of parts in your code, for instance you are declaring heroProperties inside the itemBuilder. This would trigger the for loop for every single child you pass into the GridView. I'd recommend you to check your heroProperties data. You also have a separate declaration of swipeImageGallery and you are accessing the heroProperties from inside this, which declaration is this one getting? You need to pass the complete list of hero props inside this. I can recommend you to try something like below as I have tried this just now and it seems to work, but thank you for pointing this out, I will add it to the example and the README as it is a good addition.


class _ImageGalleryExamplesPageState extends State<ImageGalleryExamplesPage> {
  final List<ImageGalleryHeroProperties> heroProperties = [];

  @override
  void initState() {
    for (var i = 0; i < remoteImages.length; i++) {
      heroProperties.add(
        ImageGalleryHeroProperties(tag: '${i}image'),
      );
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GridView.builder(
        itemCount: remoteImages.length,
        itemBuilder: (BuildContext context, int index) {
          return InkResponse(
            onTap: () => SwipeImageGallery(
              children: remoteImages,
              heroProperties: heroProperties,
              context: context,
              initialIndex: index,
            ).show(),
            child: GridTile(
              child: Hero(
                tag: '${index}image',
                child: remoteImages[index],
              ),
            ),
          );
        },
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          childAspectRatio: 0.8,
        ),
      ),
    );
  }
}

Let me know if this helps

Roxin92 commented 2 years ago

Hi @dbilgin, thanks for the fast reply first of all great library i love it. Sorry for the messy code i posted it was just snippets from the actual code but i did edit it for clarity to answer your question why i did put the loop in the itemBuilder? Is because i was stuck and just trying out where it might work but realized now it was a bad idea and why im having a separate swipeImageGallery declaration? Is because the code was getting long and messy with the overlays added, will having it separately affect the hero props? And in my case i don't have children im using itemBuilder will the hero animations still work with it?, My remote images are retrieved with a FutureBuilder so i must wait for it to complete first so i won't be able to run the loop in the initState any idea on where i can run that loop according to my code?

dbilgin commented 2 years ago

Thank you @Roxin92, I appreciate that. I didn't mean that you shouldn't use a separate declaration of swipeImageGallery, it's just that you were accessing the list of hero properties inside it directly, that could cause a problem.

I see that on this line widget.wallpaperList.add(wallpaper); you already have you images resolved from the future, so you don't need to declare the ImageGalleryHeroProperties inside the itemBuilder. For your specific case if you have to do it this way, I would declare the heroProperties before the return of the GridView and pass the heroProperties as a parameter to the swipeImageGallery. Of course at the same time you would have to declare the Hero widget inside GridTile.

If you have a repository you can share with me I can possibly help you out more, but currently this seems like more of a code structure issue rather than something with the image gallery.

Roxin92 commented 2 years ago

@dbilgin I will really appreciate that here is my repository [https://github.com/Roxin92/SwipeImageGallery.git]() Yeah i also think is do with my code the way how to structure the code it has nothing to do with image gallery im just stuck on how i will be able to loop through and apply the images ids as unique tags to the hero properties.

dbilgin commented 2 years ago

@Roxin92 your repository is empty

Roxin92 commented 2 years ago

@dbilgin Sorry just created it now and forget to import the code but actually it's working now just did what you said declared the the heroProperties before the return of the GridView and did pass the heroProperties as a parameter to the swipeImageGallery Of course at the same time have declared the Hero widget inside GridTile and everything is super now thanks for your time really appreciate it.

dbilgin commented 2 years ago

@Roxin92 that's awesome, thank you for letting me know, I'm glad it works now :) Enjoy! Will be closing this thread now since it's resolved.