The UGUI ScrollRect in Unity is a great component for building scrollable UI parts. It’s pretty easy to get started with , in-fact you can add a scroll view from the UI menu and have everything automatically setup for you. Today, I want to show you a bit of an edge case use for the scroll rect that’s not normally covered in other places. For this article, we’ll be building a scrollable image view, populated by images on your system, at runtime. This solution can also be easily adapted to work for images loaded from a website/service.
Scene Setup – Building the Unity UGUI ScrollRect
The first thing we need to do is create a new scene and add a Canvas.
Under the Canvas, create a panel, name it “Scroll Panel”
Under that panel create another panel and name it “Content Panel”
Select the “Scroll Panel” and add a ScrollRect component to it in the inspector.
Uncheck the “Vertical” box, we’ll only be scrolling horizontally today.
Drag the “Content Panel” into the content field. This tells the scrollrect what will be moving. In our case, it’s this panel.
Set the movement type to “Clamped”
Resize & Try it out
Before we add dynamic images, let’s try out the scrollrect in it’s basic form.
Resize the “Scroll Panel” so it doesn’t take up the full screen.
After that, resize the “Content Panel” so that it sticks out a bit on the right or left side like this image.
If you have your mouse over the “Scene View” and press E on your keyboard, you’ll switch to a mode that will allow you to resize easily
Press play and you should be able to drag the panel back and forth in the game view.
Image Loading
It’s time to setup the dynamic image loading. To accomplish this, we’ll use a single script named ImageLoader.cs. Create this script.
ImageLoader Code
Let’s take a look at the code now..
To start, we have two serialized fields that we’ll be modifying in the editor. The first let’s us change the image loading path and the 2nd is where we’ll set a reference to our “Content Panel”.
In the Start() method, we’re telling the application to run in the background (loading images can be slow and without this, if you click outside the window, loading will pause with the editor/game).
We also kick off a coroutine named LoadImages().
In our LoadImages method, we start by reseting our textures list, then we use the DirectoryInfo class to get all of the files in the specified imagePath.
Notice on line 31 that we’re using the .jpg extension for our search. If you want to find another type of image, you can modify that here.
We then loop over all of the files found in the folder, log out the filename for debugging purposes, and yield another method that will Load the texture.
Before we look at the load method though, take note of the second parameter we’re passing in. It’s a reference to the AddLoadedTextureToCollection method. This method delegate is being passed in as the Action parameter of our Load method so the load method knows what to do on completion. We could alternatively do the adding in the load method, but I prefer this callback style because it lets us separate our code more. In a real solution, the LoadTextureAsync method would be placed in it’s own more generic class since it doesn’t need state anymore (adding the textures in the method would make it need state and make this no-longer possible).
LoadTextureAsync() – This method is doing the actual loading as it’s name implies. Before it loads though, it needs to clean up the filename. If we’re using a local file, we need the “file://” prefix. Here, we’re simply adding that prefix (unless we hit an http endpoint). We also replace the backslashes with forward’s in here to keep everything consistent and prevent any character escaping caused by backslashes.
Next, we use the WWW class to load the file, create a new empty texture (the size doesn’t matter so we keep it 1×1), and use LoadImageIntoTexture to fill our texture from the WWW request. Remember even though we’re using the WWW request, we’re still reading a local file because of the file:// prefix.
Finally, we call the result() action that was passed in. In our case, the result is just adding the texture to a collection, but you could do any number of things here that your project may need.
CreateImages() – The last method we call is CreateImages(). This method loops through all of our textures, creates a new gameobject, set’s that gameobject’s parent to our “content” panel. Next it adds an image component and creates a new sprite from the texture to assign to it.
Setting up the ImageLoader
Select the “Scroll Panel” and add the ImageLoader component to it.
Choose a folder for the image path, make sure it’s one that has some .jpg’s in it.
Set the content field to be your “Content Panel”
Next, add a mask to the “Scroll Panel”
Uncheck the “Show Mask Graphic” box. This will prevent the image in our panel from showing and instead use that image only as a mask. It’s important to leave the image there and enabled though.
Content Panel Setup
Now select the “Content Panel”, we need to set it up a bit more.
First, add a horizontal layout group to the “Content Panel”. This layout group will make our images automatically be side by side in a horizontal view.
Set the spacing to 5 and the child alignment to “Middle Center”
Now add a ContentSizeFitter to the “Content Panel”.
Set the Horizontal Fit to “Preferred Size“.
Without the content size fitter, the panel won’t re-size to the # of images we load. This would cause it to not be scrollable (or only be scrollable to the size we pre-set it at).
Testing it out
That’s everything we need to do to set it up, so let’s press play and see what happens.
Conclusions & Extension
This article shows some of the basics for loading images at runtime and setting up an auto sizing scrollrect. The process is pretty simple, but for a real world project you probably want to polish it up a bit. An easy thing to do first is create a prefab for your images instead of creating them in code using new GameObject. Using a prefab, you could adjust the size, setup some frames, make the images interactable or more. Another thing you may want to add is some loading notification. Because loading images can take a while, it’s good to have something other than a debug.log to let your users know that loading is actually happening and the app hasn’t completely frozen.
Project Download
Having problems re-creating this and want to download the sample project? You can get it here: https://unity3dcollege.blob.core.windows.net/site/Downloads/Scrolling.zip