Skip to Content

Adaptation Framework – Guideline : the "One Size Fits All" strategy

Printer-friendly versionSend to friendPDF version
Intermediate

Here you will learn how turning your source code into a real "write once run on any screen size" implementation, providing detailed explanation of the advanced features related to a "one size fits all" strategy.

Introduction

In this tutorial we provide a step-by-step illustration of the so-called "One Size Fits All" strategy to be used with our Adaptation Framework.

The purpose of the "One Size Fits All" strategy is to define one unique Layout and one Master Skin to target any screen size.

Before reading this tutorial, you must be familiar with the Adaptation Framework modules.

If it is not the case yet we suggest you read the following articles before:

Targeted Application

Let’s get back to the “Nature Store” sample, already used in a previous Adaptation Framework tutorial.

We will use this sample to illustrate a slightly different Skinning & Layouting strategy. The goal now is to define one unique dynamic Layout and one master Skin. Both of these will fit by themselves almost all adaptation cases.

One Dynamic Layout

First thing is to define the page layout. The idea here is to define proportional values for containers width & height so that they will automatically get adapted to any screen.

With the One-Size-Fits-All strategy we want to avoid defining as many skins as screen size families, so this implies that our Layout does not refer to skin elements sizes, it has to be dynamic by itself.

So first let’s create a main.xml file and declare our page layout in the adaptation XML file

Tip: In the first Adaptation Framework tutorial we chose to define carousel items size in the Skin and then to compute the number of visible items dynamically in the RSP. In this sample, we chose another strategy: we define in the layout the containers for 5 items and then in the code we resize carousel icons to fit those containers. The chapter "About The Carousel Items Adaptation" will tell you more about this.

The Master Skin

Now that we have our layout, let’s create a Skin with all our static assets. With the One-Size-Fits-All strategy, we create a high-resolution Skin that we call “master”. All the bitmaps in this master skin will have to be resized at runtime, given the layout computation.

This means that for each bitmap, we have defined in the master skin the layout container they have to fit in and the resizing constraint to be applied among the following: keep-ratio, keep-ratio-width, keep-ratio-height, stretch, stretch-width, stretch-height.

So let’s declare our master skin in the adaptation.xml file:

And now the 600x800.xml skin, with the resizing parameters for each bitmap:

2

Bitmaps Adaptation

Now that we have the layout and the master skin, let’s see how we use it in the RSP code.

First thing is to retrieve the Skin and Layout instances, as usual :

<% // Get the connector using the ConnectorManager AdaptationConnector adaptationConnector = StzConnectorsManager.getAdaptationConnector(stzRequest.getService(), 0); // Begin a transaction for the current request. // The skin theme is 'stz', and we want the 'std' layout set AdaptationTransaction tx = (AdaptationTransaction) adaptationConnector.beginTransaction(stzRequest, "stz", "std"); //accessing the skin Skin skin = tx.getSkin(); //accessing the layout Container layout = tx.getRootContainer("main"); %>

Now we need to apply the resizing policy to the skin’s bitmaps. This is done using the AdaptationUtils API:

<% ImageResult listItemBg = null; try { AdaptationUtils.addImage("background", 3600000/*ttl*/, stzRequest, authoring, skin, layout); AdaptationUtils.addImage("header", 3600000/*ttl*/, stzRequest, authoring, skin, layout); AdaptationUtils.addImage("footer", 3600000/*ttl*/, stzRequest, authoring, skin, layout); AdaptationUtils.addImage("rightArrow", 3600000/*ttl*/, stzRequest, authoring, skin, layout); AdaptationUtils.addImage("leftArrow", 3600000/*ttl*/, stzRequest, authoring, skin, layout); listItemBg = AdaptationUtils.addImage("listItemBg", 3600000/*ttl*/, stzRequest, authoring, skin, layout); AdaptationUtils.addImage("listItemBgFocused", 3600000/*ttl*/, stzRequest, authoring, skin, layout); } catch (Exception e/*Resource not found*/) { stzRequest.getLogger().error("Cannot load skin resources !", e); } %>

Tip: The AdaptationUtils.addImage(…) method returns an ImageResult instance so that you can know the resulting width & height of the bitmap after the resizing policy is applied.

The stream ID of the image is set to the image ID in the skin. Then you can declare the Bitmap nodes like this:

">

The core part of the “One-Size-Fits-All” strategy is implemented. Now you can actually see the result of emulation for several screen sizes:

 

About The Carousel Items Adaptation

In the layout we define five items for the carousel, so we set the number of visible items to 5. The carousel displays one focused icon in the middle and unfocused icons on the sides. Unfocused icons are downsized compared to the focused one. As a result, after the resizing of the unfocused icons is done, we may have some space left, especially in landscape screens (because the resizing keeps a square ratio within each item box).

So if we want to use this left space, we have two options: dispatch the space left to get more icons displayed or dispatch the space left as padding.

The following snapshots explain the two options.

 

In the provided sample project the option 1 has been selected, though the code for option 2 is also provided. Below is the code extract for the carousel left space computation and usage:

<% // Padding is defined in the layout int padding = (int) layout.getChildByIdRecurs("Padding").getWidth(); // Total width of the carousel container float availableWidth = layout.getChildByIdRecurs("Carousel").getWidth(); /** * Spaceleft usage * Layout has been defined for 5 items, but if there is engough space left to add some, let's do it */ float spaceLeft = availableWidth - (nbItems - 1) * (unfocusedItemBoxSize + padding) - focusedItemBoxSize; /* * OPTION 1 : Dispatch the spaceleft to get more icon displayed */ int nbIconDisplayed = 5 + (int)(spaceLeft/unfocusedItemBoxSize); // Don't want an even number of icon of esthetic reason if(nbIconDisplayed %2 == 0) nbIconDisplayed--; /* * OPTION 2 : Dispatch the spaceleft as padding */ /* int nbIconDisplayed = 5; padding += (int)(spaceLeft/(nbIconDisplayed-1)); */ // RequestParameterContext RequestParameterContext context = new RequestParameterContext(); […] // Display context.addParameter(Carousel2DParameters.ICON_UNFOCUSED_SIZE, unfocusedItemBoxSize + " " + unfocusedItemBoxSize); context.addParameter(Carousel2DParameters.ICON_FOCUSED_SIZE, focusedItemBoxSize + " " + focusedItemBoxSize); context.addParameter(Carousel2DParameters.NB_ICONS_DISPLAYED, nbIconDisplayed); context.addParameter(Carousel2DParameters.PADDING, padding); %>

So now that we have adapted the number of items of the carousel, our application looks like:

 

Specific Adaptation

When we look at our intermediate result #2, one may think that the “Back” right soft key is too big in the 320x240. This is because the size of the soft key container is set to 20% in the layout description, for every screen.

So we feel the need here to “override” some values of the layout for a specific screen size. This can be done using Layout external values and Skin inheritance.

Layout External Valuation

In the layout description, you can define some width & height values as external using the prefix “@”. An external value is supposed to be defined in the skin description. The external identifier can match either a skin image or a skin property. In case it matches an image the width or height container value will be set to the image width or height value. In case it matches a property, the property value is parsed just as if it was inlined in the layout description (can be percentage or pixels value).

Here is how to define an external size value in the layout:

[…] […]

And this is how the SoftKeyWidth property is defined in the skin:

[…] 20% […]

Skin Inheritance

Once the sensitive value has been externalized in the skin, you can override it for a specific screen size thanks to skin inheritance. Skin inheritance allows defining a child instance that can redefine only part of the parent skin instance.

For instance here we want to redefine the SoftKeyWidth property for the 320x240 screen size only. Here is how we do it:

48

And here is the result:

What We Finally Get

Finally with only one Skin and one auto-adaptive Layout description we managed to get our application adapted to any screen size.

Of course for a more real-life application you may need to add some more skin overriding or device properties adaptation criteria but the global setup is there: your application is now ready to run on any screen size with no extra cost.

Share this