Ti.UI.Views & backgroundSize:cover

As documented, background images will be scaled to fit the view’s dimensions. You can use nine-patch images on Android or background[Left|Top]Cap on iOS to determine what part is scaled, but scaled it is.

Full-size background photo

If you want your app to have a nice background photo regardless of the screen size and aspect ratio (I’m looking at you Android!) you will need the image to fill the – initially unknown – dimensions of the view while respecting the image’s aspect ratio. Out of the box, there is no solution for this in Titanium.

Custom view factories

Fortunately, in both Classic and Alloy you can use custom view factories. So I created one wrapping Ti.UI.createView that adds support for the background-size:cover property known from CSS.

How it works

If you set a width and height property, it will convert any unit to the required px for the device. If you don’t, it will add a postlayout event listener to get them when the view is layed out. Of course the resized images are cached, but if you don’t even want to wait for postlayout, then use the backgroundTarget property to pass a string to identify the target. Use this only if you are sure the layed out dimensions will always be the same for that particular view.

How to use

Assuming you have ui.js under app/lib, use it like demonstrated in the following example. Of course best practice would be to have these properties in the TSS.

<Alloy>
    <View module="ui" backgroundImage="images/background.jpg" backgroundSize="cover" backgroundTarget="myView" />
</Alloy>

How it compares

Scaled like demonstrated in the docs:

The same images using backgroundSize:

iOS-simulatorschermafbeelding 7 feb. 2014 11.16.16

App imagineer: Imagining, Engineering & Speaking about Native mobile Apps with Appcelerator Titanium & Alloy • Meetup organizer • Certified Expert • Titan


Comments

  • Silvio

    I’m so sorry because i’m a beginner with Titanium, but I still have problems with your script. In fact i can’t configure it to make it running…
    Where I have to put your ui.js script?
    Why do you have just , and instead I find ?
    The goal I looking for is to make a blurred photo based template, but the default Titanium’s behavior is to stretch my image and it looks not very professional for layout design.
    So I found your “cover” approach very familiar coming from CSS3, but I can’t understand what it wrong with my setup…

    Thank you

  • Sander

    Too bad it can’t be used in ListView templates, at least I can’t. I suppose because templates only support a specific subset of widgets. It would be nice to be able to use this approach for list item backgrounds. Is there any way to work around this?

  • Fokke Zandbergen (@FokkeZB)

    @Sander There’s a fundamental difference between ListView and other views that is not so evident when you are using Alloy. Read http://docs.appcelerator.com/platform/latest/#!/guide/ListViews-section-37521650_ListViews-Concepts for more information. In short: ListView UI is created on the native side, not on the JS side, where widgets live – thus, making them unusable.

  • Hugo Freire

    Not Working on landscape here

  • Fokke Zandbergen Post author

    @Hugo how exactly is it not working? You mean when you change the orientation it won’t update the image? That’s correct. You’d have to adjust the code in order for that to work.

  • Jeremy Law

    First of all, this is awesome!

    I did, however, have some trouble getting it to work with a ScrollableView on Android. The images would sometimes not appear, or pop into view a second or two after switching pages. I assume this has something to do with the postlayout event?

  • fokkezb

    Yes, that’s correct. It might not work very smooth in that scenario.