How to use the Feathers ImageLoader component

The ImageLoader class wraps starling.display.Image inside a Feathers component to add additional features. For instance, you can easily load an image from a URL and automatically convert it to a texture that is fully managed by the ImageLoader. The texture will be disposed when the ImageLoader is disposed. A number of other useful properties have been added to ImageLoader. See below for more details.

The Basics

First, let's create an ImageLoader control, pass in a texture to display, and add it to the display list:

var loader:ImageLoader = new ImageLoader();
loader.source = texture;
this.addChild( loader );

Alternatively, you can pass a URL to the source property to load an external image:

loader.source = "http://www.example.com/image.png";

The URL may point to any image file that may be loaded by flash.display.Loader to create a flash.display.BitmapData object. The loaded image will be converted to a starling.textures.Texture.

Events

You can listen for Event.COMPLETE to know when the image is fully loaded:

loader.addEventListener( Event.COMPLETE, loader_completeHandler );

The listener might look like this:

function loader_completeHandler( event:Event ):void
{
    // image loaded and texture ready
}

You can also listen for errors to know if the ImageLoader is unable to load the texture:

loader.addEventListener( Event.IO_ERROR, loader_ioErrorHandler );

The listener for Event.IO_ERROR might look like this:

function loader_ioErrorHandler( event:Event, data:IOErrorEvent ):void
{
    // loader error
}

The data parameter in the function signature is optional, as always. It is a flash.events.IOErrorEvent that is dispatched by the internal flash.display.Loader used internally by the ImageLoader.

Similarly, you may listen for Event.SECURITY_ERROR. The data property of the event is a flash.events.SecurityErrorEvent dispatched by the internal Loader.

Caching Textures

By default, the ImageLoader will always create a new texture every time that it loads a source from a URL. In components like List, Tree, and GroupedList, it's common for the same URL to be loaded multiple times by one or more ImageLoader components. This can use extra bandwidth and affect performance.

If enough memory is available, it's possible to store the loaded textures without disposing them. An instance of the feathers.utils.textures.TextureCache class can be shared by multiple ImageLoader components, and if a URL has already been loaded, the texture will be taken from the cache instead of reloading the image file and creating a new texture.

To use, simply pass the same TextureCache instance to the textureCache property of multiple ImageLoader components:

var cache:TextureCache = new TextureCache( 30 );

var loader1:ImageLoader = new ImageLoader();
loader1.textureCache = cache;

var loader2:ImageLoader = new ImageLoader();
loader2.textureCache = cache;

The parameter passed to the TextureCache constructor specifies how many textures should be stored in the cache. This limit affects only textures that are not currently displayed by any ImageLoader using the cache. The parameter defaults to int.MAX_VALUE, but a smaller value is recommended to avoid using too much memory and crashing your application. In this case, we've chosen 30.

For a List, we might use a TextureCache for icons or accessories that are loaded from URLs:

var cache:TextureCache = new TextureCache( 15 );
list.itemRendererFactory = function():IListItemRenderer
{
    var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer();
    itemRenderer.iconLoaderFactory = function():ImageLoader
    {
        var loader:ImageLoader = new ImageLoader();
        loader.textureCache = cache;
        return loader;
    };
    return itemRenderer;
};

The dispose() method of the TextureCache should be called when the List or other component using the cache is disposed. The TextureCache does not automatically know when it should dispose its stored textures, much like how a starling.display.Image will never dispose its own texture property because the texture may still be needed elsewhere.

In the following example, let's assume that we stored a TextureCache instance in a savedTextures member variable in one of our screens:

override public function dispose():void
{
    if( this.savedTextures )
    {
        this.savedTextures.dispose();
        this.savedTextures = null;
    }
    super.dispose();
}

When the screen is disposed, we'll simply dispose the TextureCache.

Other Properties

You can snap the position of an ImageLoader to the nearest whole pixel using the pixelSnapping property:

loader.pixelSnapping = true;

Pixel snapping is most useful for icons where crisp edges are especially important.

When images are loaded in a component like a List, it's often more desirable to avoid creating new textures on the GPU while the list is scrolling. Since texture uploads are expensive, this keeps the list feeling smooth and responsive.

loader.delayTextureCreation = true;

Set the delayTextureCreation property to true when the container starts scrolling and set it back to false after scrolling finishes. While this property is true, the image may load from a URL, but the BitmapData will be kept in memory without being converted to a texture on the GPU. Once the property is set back to false, the texture will be created immediately.

If desired, we can set the textureQueueDuration property to a specific number of seconds. When delayTextureCreation is true, the loaded image will be converted to a Texture after a short delay instead of waiting for delayTextureCreation to be set back to false.

When you resize a regular starling.display.Image, it may distort. ImageLoader allows you control whether the image maintains its aspect ratio within the dimensions of the ImageLoader:

loader.maintainAspectRatio = true;

When the maintainAspectRatio property is true, the image may be letter-boxed inside the ImageLoader, adding transparent edges on the top and bottom or on the left and right.

You can use the isLoaded getter to know if a texture is fully loaded (in addition to listening for Event.COMPLETE, mentioned above):

if( loader.isLoaded )
{
    // ready
}
else
{
    // not loaded
}

You may set the scale factor of the loaded texture:

loader.scaleFactor = 0.5;

Using this value, the texture will be scaled to an appropriate size for Starling's current contentScaleFactor.

Finally, just like starling.display.Image, ImageLoader allows you to customize the color and smoothing properties:

loader.color = 0xff0000;
loader.smoothing = TextureSmoothing.NONE;