Flutter Tutorial – #1.10 – Image Carousel & Carousel Slider [Gallery Detail]

Introduction

Welcome to Himdeve development, where we are preparing the best tutorials to make your mobile app development easier and more efficient.

Goal

  1. We will create a detail page for the image gallery
  2. We will learn how to work with PhotoView and PhotoViewGallery
  3. We will learn how to create our own Image Carousel and also how to use the Carousel Slider component
  4. We will show how to create a ripple effect animation on image tap action
  5. We will learn how to zoom in, zoom out and rotate an image
  6. And we will also learn how to work with Flutter widgets like Stack, Positioned and InkWell

Procedure

First we open our existing application from the previous tutorial and we open the portfolio_gallery_sub_page.dart file. This will be our entry file for this tutorial.

In the _buildContent method for the SliverGrid delegate, we are returning the _buildImageWidget method. We will extract this method into a new file portfolio_gallery_image_widget.dart in the components folder. It will be a Stateless Widget with two required parameters – imagePath and onImageTap. ImagePath represents the path to the image and onImageTap is a void callback function that will respond to a click on the image.

Ripple Effect

The Ripple effect is a small wave-like pattern that usually forms on the surface of a liquid when something drops on it.

In Flutter, the ripple effect is a visual touch feedback on user interaction with the components on the screen.

Flutter provides an InkWell widget to perform this effect.

InkWell can wrap individual widgets to provide a layer for the ripple effect.

InkWell has the onTap attribute in which we insert our onImageTap callback method.

How to combine InkWell and our image together?

In Flutter, the Ink component is ideal for this job, using its Ink.image constructor.

The Ink.image constructor has the following attributes:

  • image: in which we use the AssetImage provider with the path to the image in our assets folder.
  • fit: in which we insert BoxFit.cover.
  • child: where we put the InkWell widget.

To give the ripple effect a place where it can show up, we wrap the Ink.image constructor in a Material widget.

Copy to Clipboard

Consequently, the whole class looks like this.

Copy to Clipboard

We go back to the portfolio_gallery_sub_page.dart file and we return the PorfolioGalleryImageWidget widget instead of _buildImageWidget method. We set the ImagePath attribute to a specific image path and we insert the Navigator.push method to change the page in the onImageTap attribute. We want to change it to the PortfolioGalleryDetailPage. We use MaterialPageRoute, which we create in the _createGalleryDetailRoute method. PortfolioGalleryDetailPage will have imagePaths attribute, which represents the image path list and currentIndex attribute, which represents the currently selected image index.

Copy to Clipboard
Copy to Clipboard

PortfolioGalleryDetailPage

We need to create the PortfolioGalleryDetailPage class first. Therefore, we create a portfolio_gallery_detail_page.dart file in the pages/portfolio/ folder.

It will be a Stateful Widget. We define the required imagePaths and currentIndex parameters.

For its state – _PortfolioGalleryDetailPageState class, we define two variables – _currentIndex and _pageController.

And in the initState method we initialize them.

Copy to Clipboard

To get currentIndex from Stateful Widget to State class, we use a getter – widgetwidget.currentIndex.

The PageController will manage the pages of our images to achieve the effect of Image Carousel. We define the initialPage argument to display the currently selected image.

In the build method, we will return the Scaffold widget, to which we set the black background color and we add the AppBar widget to it to have a back button to return to the previous page. We also define its background color to black. We insert the _buildContent() method into the body attribute.

Copy to Clipboard

Stack

We will define the _buildContent() method, where we return the Stack widget.

The Stack widget allows us to make multiple widgets overlay each other. In our case, we’ll use this by first inserting a widget that displays the image in the image gallery, and on it, at the bottom, we display the indicator bar of our images from the list.

Copy to Clipboard

PhotoViewGallery – Image Carousel

In the _buildPhotoViewGallery method, we return the PhotoViewGallery using the PhotoViewGallery.builder constructor. To explicitly define images in a gallery, we can use the PhotoViewGallery() constructor. However, the PhotoViewGallery.builder constructor creates images in the gallery dynamically.

In order to use PhotoViewGallery at all, we need to define a photo_view dependency in pubspec.yaml file.

Copy to Clipboard

The PhotoViewGallery has a built-in PageView with all the effects, ensuring a complex pagination between images. And thus solved the basic functionality of Image Carousel.

The PhotoViewGallery.builder constructor has several attributes. We are currently defining some of them.

itemCount

– represents the number of items and we insert the widget.imagePaths.length here. Again, we can notice that the imagePaths parameter, defined in the Stateful Widget, is obtained by the getter – widget.

builder

– creates items in the gallery. We return here the PhotoViewGalleryPageOptions object, a wrapper that wraps the image and its associated options.

PhotoViewGalleryPageOptions

We also define a few attributes here.

imageProvider

– where we put the AssetImage provider with the current image.

minScale

– defines the minimum size that the image will be allowed to shrink.

maxScale

– defines the maximum size that the image will be allowed to enlarge.

We also define additional PhotoViewGallery.builder attributes.

enableRotation

– allows the user to rotate the image on the screen.

scrollPhysics

– allows us to change the paging effect of individual images.

pageController

– here we define our _pageController.

loadingBuilder

– this attribute makes more sense when we want to load an image from the Internet, which may take longer to load depending on the speed of the Internet. However, we put CircularProgressIndicator here and we wrap it with the Center widget.

onPageChanged

– is a callback method that is called on a change of the displayed image in the gallery when paging. It has an index parameter which we set to our _currentIndex variable.

backgroundDecoration

– defines the background behind the image, e.g. a color.

scrollDirection

– defines the scrolling direction. We can scroll both horizontally or vertically.

Copy to Clipboard

PhotoView

If we don’t want to create a gallery but want to display only one image, we can use the PhotoView class instead of PhotoViewGallery, where we can also use the previous parameters.

Copy to Clipboard

Positioned

Now we can create the second method defined in the Stack widget_buildIndicator().

In this method, we return the Positioned widget, which determines where a widget-child is located in the Stack.

It has several attributes. We set the bottom attribute to 0 to ensure that the bottom of the child-widget is placed at the bottom of the Stack widget.

We set both the left and right attributes to 0. Since both attributes are set to 0, the child-widget touches the edges of the Stack widget with its edges. So it is stretched to the width of the Stack widget.

Dotted Indicator

Then we insert the Row widget into the child attribute, centering it using the mainAxisAlignment attribute. And for the Row‘s children attribute, we’ll use a map function to create a widget for each image in the list. In our case it will be a small dot representing the image in the gallery.

We create this dot in the _buildDot method, which will have the path to the image as a parameter.

Copy to Clipboard

In the _buildDot method, we create a Container widget and we insert a circle-shaped BoxDecoration into the decoration attribute using the shape attribute. And we set the color to gray for all the dots representing the images in the gallery except the one that represents the currently displayed image. We set the color to white for this dot. We can determine whether this is the currently displayed image by comparing the _currentIndex parameter with the index obtained by the indexOf function of list.

Copy to Clipboard

Image Carousel Slider

If we wanted to display a small image carousel slider at the bottom of the screen instead of dots bar indicator, we could use the carousel_slider library. In pubspec.yaml file we define carousel_slider library with current version ^1.4.1.

Copy to Clipboard

And in the portfolio_gallery_detail_page.dart file, in the _buildIndicator method, we insert the _buildImageCarousel() method to the child attribute of the Positioned widget.

Copy to Clipboard

The _buildImageCarousel method returns the CarouselSlider widget. Again, we have an option to use the explicit CarouselSlider() constructor or the dynamic CarouselSlider.builder() constructor.

We use the dynamic constructor CarouselSlider.builder().

This constructor has the following attributes.

itemCount

– where we set the number of items in our image list

itemBuilder

– creates items. In our case, mini images, for which we can again use our PortfolioGalleryImageWidget, which has already defined the ripple effect. We insert the path to the image to the required imagePath parameter. And in the onImageTap attribute we call the jumpToPage function of the PageController with the index of the selected item.

height

– sets the height of the CarouselSlider.

enlargeCenterPage

– specifies if the current page should be larger then the side images, creating a feeling of depth in the carousel.

viewportFraction

– it is the fraction of the viewport that each page should occupy. We set this attribute to 0.21. Which means that every page, or image in our case, will fill 21% of the size of CarouselSlider.

initialPage

– defines the current page of CarouselSlider.

Copy to Clipboard

Conclusion

And with this is our tenth part of this first series of Flutter Tutorials completed and of course you can find the complete source code on the githube.