Add Tablet Support to your App

About Tablet Support

People might like them or not, but tablets are there, and sometimes they can even be useful.
Depending on the market you’re in and the functionalities of your app you should consider adding tablet support to your app.

For best result, you want to design a new tablet-specific layout, but it can be incredibly expensive and time-consuming – it’s basically like building a brand new app!

The other option is to adapt your existing layout to a bigger screen with some tricks.
The result won’t be as good as with an ad-hoc layout, but you can certainly expect nice results in most cases.

It’s important to define the Minimum Viable Product with your team before starting.
Select a limited set of features that need to be available and work smoothly.

Layout Precautions

First of all, ensure all of your app views are based on a liquid layout.
Linear or Relative Layouts for Android, and Auto-Layout and/or Size-Classes for iOS are a must.
When designing your layout, keep in consideration the following :

  1. Height should be constant where possibile.
  2. Views should be anchored to views above them
    So, by keeping height constant, the view Y position is always defined.
  3. Views should be anchored on both left and right
    This way your UI will get wider along with other elements.
    Top level views should be anchored to the screen size.
  4. Containers should have a maximum width set.
    So that you don’t have tremendous gaps between elements, like a label and its value at the exact opposite of the screen.

Here is an example layout that follows these indications.

| V1       |         |    V1 is the parent layout
|          B         |    V2 height is fixed
|          |         |    A is V2 m-left V1
|     +----------+   |    B is V2 m-top to V1
|     | V2       |   |    C is V2 m-right to V1
|--A--|          |-C-|    V2 height is fixed
|     +----------+   |    D is V3 m-top to V2
|          |         |    E is V3 m-left to V2
|          D         |    F is V3 m-right to V2
|          |         |    V3 height is fixed
|     +----------+   |
|     | V3       |   |
|--E--|          |-F-|

By setting these constant margins and heights you are exempt from defining a bottom margins, which makes a lot easier to stack views vertically, plus, V2 and V3 widths are now dynamic.
Following this approach limits your options but make implementing the layout much easier.

I’ll soon write down a quick Auto Layout guide.

Android developers should consider adding an ad-hoc layout for landscape!
Create a “-land” directory and add there your new layouts.
To start, identify the most troublesome layouts, copy-paste there your portrait xml and start working from there.

Device Orientations

Once your layout is ready, start by adding support for all possible device orientations.
The layout doesn’t need to be perfect, and it might even not look good at all.

Once you have something good enough in landscape, try rotate the device and ensure you also support transition for rotation.
In iOS, consider implementing viewWillTransition(to:with:) in your View Controller.

Finally, if you have any code that interacts with the UI, it is essential for you to remove any hardcoded value from there – Those shouldn’t have been there in the first place!
Instead of using plain constant values, consider using lazy properties in iOS or define a dimen.xml in Android.
If you are placing elements from code, you should create layout rules for them using Layout Params and Layout Constraints or Anchors, depending on the platform.

Collections of UI Elements

TableViews, ListViews, CollectionViews and such might be tricky and expensive to fix.
Ensure you use linear/relative/auto layouts also in row elements.
If those views are capable of displaying the content in columns, consider adding more columns.
In most cases you will have a single column on phone, and two or three on tablet.
Finally, make sure elements are properly sized and maintain correct proportions in landscape and on larger screens.

In iOS, consider migrating from UITableView to UICollectionView, it might be easier than you expect.
In Android, you might need to define a custom ListView in order to get two columns, but it should be worth it.

Start Refactoring

If you followed my suggestions, by now, your app should be usable in any orientation, on both phones and tablets.
But the result is probably not thrilling.
There are a few very cheap style tricks you can apply to get a better result, some of them have alreadybeen mentioned.
I suggest you to take on a single screen at time, starting the the main one.

1. Fix size of system elements

It is sometimes difficult to met business expectation with standard UI elements, ensure the sizes of those elements are in harmony with the standard one
For example, in iOS, it is not so unusual to have custom navigation bar, ensure the view is smaller in landscape.

Example of how a Custom Navigation Bar.

2. Define maximum width for certain elements.

Add constraint to your layout so that it doesn’t widen too much in landscape.
You can do so easily by setting a max-width and center horizontally the view in its parent.

There are empty spaces because I had to remove some UI elements (logos, ecc) before publishing the post.

3. Use more columns, but only where needed

If your layout currently shows the content in a single list, say, using one single column, you might think of adding a second column.
In iOS this can be easy by changing your class from UITableView to UICollectionView, the default Flow Layout will do for most use cases.
Android developers can either use a GridView or implement a custom ListView with n columns.

Before adding more columns, think about what are you presenting to the user.
Can you show more data per record instead of just more records?
<Example coming soon>

4. Merge different Screens together

This is the last step to finish refactoring. Is there any screen you can merge into an other now that you have more space?
Where possibile, you should consider merging screens for any master-details relation.

Most important 
Consider replacing frequently used screens with a sliding panel or a navigation drawer.
A good example of this is Facebook for iPad, where home and notifications are displayed on the same page.
This should be easy when working with fragments, but it might be a little trickier on iOS.

That’s all folks!

For now this is what I have to say – I will keep updated the post with new suggestions.
I hope my advices are useful, feel free to contact me for any need 😁

Swift Arrays & Memory

Here are some thoughts I’d like to share when it comes to Arrays in Swift.
If you’re looking for more information, check out this very good post about memory management in Rust and Swift.

Contiguous Memory

Apple Docs are quite explicit :

For arrays [memory] storage can be a contiguous block of memory or an instance of NSArray.

Arrays are stored in a contiguous block of memory, of course they are.
This is nothing new, but if that’s so, what happens when you append an element to an Array?

Memory Relocation

Relocation occurs when the size of an object exceeds the memory available in its block.
Seems so obvious while reading, isn’t it?
The object is moved to a larger block and the address changes.
This is also possible causes of Memory Leaks, but I leave this story for an other day.
Suppose you are in a very busy and threaded environment… An array changes address… What will happen? Will all the threads be able to access the values properly?

Bad Access and Heap Corruption

Sometimes things might go bad.
You will get a shitty EXC_BAD_ACCESS with little-to-no explanation.
If you’re lucky, you will notice that the address of the incriminated array in the debugger differs from the one that caused the error – of course, it has been moved!
Put together relocation and leaks, and in the worst case you’ll get an Heap Corruption.

How to avoid Array Relocation

My advice is to take this seriously from the start.
Do not fear to write a few more lines of code and reserve capacity for array elements, so they won’t be relocated.
This can be done easily by calling the method reserveCapacity(:_) :

var fruits = ["banana", "strawberry"]
fruit.append("google") // Not a fruit, but for par condicio
fruit.append("an other banana")

You can also reserve memory you don’t use, which might be an easy option if you don’t know the exact number of elements.

Extension of the day

I love extensions.
If you are particularly lazy – like I am, that’s why a love extension – check this simple extension, that will allow you to init an empty array and reserve capacity in one line.

var fruits = [String](withReservedCapacity: 5)

Oh my blog!

I wanted to start blogging for a while, but didn’t have much ideas for a good start.

In short, I decided to start publishing stuffs without thinking too much about it.

I am a developer, my life isn’t too exiting, but I hope someone will find something useful along occasional stories of beer and stuffs.