When comparing Android to iOS, I found it quite ironical that the one with the "ugliest" apps is the one that gives the developer the best tools to achieve a beautiful, consistent and crisp UI.
Let me explain you why. I will compare mostly iOS with Android, but sometimes I'll reference CSS/HTML when neither of them are good enough to tackle the matter at hand.
When talking about android, I will focus on Eclipse only. I know that android studio is the thing now but I haven't had the time to explore it and, in theory, is still beta.
I will set up the following dimensions to act as the basis of my evaluation:
- File format
- Target audience
- Modularity and reuse
- Multiple Screen sizes
Then I will briefly mention some tools that were created to try to solve most of these problems. I would love to have some feedback from you. Do you feel these annoyances when designing interfaces for iOS? How do you tackle them? What tools do you use to mitigate these effects? What other UI/layout systems have you used that deal with these problems in a better way and how do they handle them?
Android layout files are just simple xmls. You can always check the android developers site to see what attributes can be used in each element and what are their possible values (or just use eclipse auto-complete functionality). This allows us to quickly change the file and see the visual modifications that the change triggered, while in iOS its nearly impossible since one slight nudge of an element can result in a cascading set of seemingly unrelated changes to the underlying xml.
Just try to understand what changed in a xib by looking at the diff. Most of the times it's almost impossible.
The other problem with xib being a "closed" (by close i mean that there is no publicly available document type definition, and the definition itself seems to be changing all the time from the versioning information that i end up seeing xcode putting all over the xib) xml, is that it makes it very hard to develop tools to help create and visualize them, tools that could enhance the design and layout experience and fill in the gaps left by Xcode's IB (Interface Builder).
Are xibs meant to be used by developer or by designers? They could be used by a designer, but I really don't think that they would like the amount of settings that are possible to change for a given element nor that lack of attributes that are only possible to change via code. And don't even try to turn on auto layout. Seriously. We'll touch that subject later on.
On the other hand, the system feels too contrived and GUI-based for a developer to handle. It's imprecise and clumsy. On Android, most of the times i am dealing with the xml because that is where I am more comfortable. I can quickly add a child to an group element, change widths, heights and rules of alignment in a precise and deterministic way.
I don't have to struggle with a GUI to try to get what I really want. In Interface Builder, I don't know what the effects of a given change are because, most of the times, the system tries to reflow the other elements and messes up the entire layout. I end up with constraints added, removed or changed without my order.
Didn't it ever happened to you clicking on some key by mistake while an element was selected and wondering if you broke something? Did it do something? Did it broke the layout? Did some magic constraint that was necessary got destroyed? Let me just check the git diff... oh wait.. Let me resize it then to see if nothing is broken...
It just feels that xibs were not meant to be used by developers, but they don't seem to be good enough for designers either, so they are just there, in the middle of a spectrum, not really knowing what their target is.
Modularity and reuse
UI design, like any other design, is enhanced by applying a core family of principles that promote the separation of concerns and the DRY concept.
We are all familiar with the concepts of modularity and reuse. Each component serves a specific purpose and components can be integrated into each other. In android you can include layouts, as a partial, into another view. Not only that but you immediately see the included layout in the context of your current view in eclipse preview function. This allows us to apply the same universally good principles of OOD to layout.
In iOS the concept of inserting a custom layout into another is possible, but you won't get any visual feedback when previewing the final result in IB so its usefulness is greatly diminished. What's the point of importing a view if i can't see how it ends up looking? Most probably you will end up with a "main" or "root" xib that is made up of a bunch of blue views with the title "custom view" in the middle of it. Great.
Any application has a style. It has some color palette, some typical font style, perhaps some common gradients, etc. So it should be as easy as possible to define some styles that could be easily applied in any view of your application UI right?
Styling in android is quite good. You can define styles, like in CSS, that can be applied to multiple views. The cascading principle still applies because in can inherit a given set of attributes from a style and override the ones you want to change for that particular element.
On the other hand in iOS there is really no way to do that using xibs, only in code and only partially. Well, you can create your custom UIButton but again, you end up with a custom view, without being able to see how UI will look without running the entire app.
Multiple screen sizes
In android you can use linear and relative layouts to define overall rules of how elements should be positioned for a given height or width. Then you can preview the layout in multiple screens at the same time and watch the changes take effect in real time.
On iOS, this problem wasn't really relevant because there was only one screen size, the iphone. Well, but then ipad came. Ok, so now we have to create two xibs. And then the 4 inch iphone came. And then apple really thought that the current solution is not scalable, that perhaps, just perhaps, there will be a need to handle multiple screen sizes in a unified way. So what can they do? Lets create this thing auto layout to solve this problem.
Well, the thing is that auto-layout is over-engineered. It feels like Apple just tried to reinvent the wheel and ended up with a squared one. It asks the developer to stop thinking about widths, heights and alignments and to start thinking about constraints as the first class citizen. Oh, and throw in a couple of concepts like content hugging and priority there just to make things easier.
And worse than being hard to understand is being hard to "debug" it. How many times happened to you not being able to resize a view to a width/height to test the limits of your layout. It just stops at one point because it cannot resolve the constraints that you have given to it. But where is the feedback? What constraints have i violated? How can i change them? Good luck.
And the thing is, at least for me, that are things that i could do with resizing masks that i can't (or don't seem to find a way to) do with auto-layout. Let's show a simple example:
Here i want that the distance between the left-most and right-most squares from the closest edge to be 10% of the container view, while maintaing the distance between the squares themselves.
How can you achieve this with auto-layout?
And imagine if i want to show hide an element depending on the width like responsive design on web development does. How can i achieve this? To the best of my knowledge the only possible way is to handle it with multiple xibs or handle it with code.
The multiple xib solution is just a mess because you would have to repeat yourself each time you wanted to changed the layout that had the element that would be conditionally displayed. Just to be honest with you there isn't a perfect solution in android for this too. But, since you can import elements , and those elements are picked in runtime according to the current device specifications, the amount of layout to you need to duplicate is minimal. CSS media queries would be great here.
Well, there comes a time when the UI elements provided out-of-the-box are simply just not tailored for you needs. So what do you do? You create your own elements.
What do android and iOS have to offer in this regard? On iOS you can create your custom view, extend it from UIView easily enough, but from that point on your view is a custom one, subject to the same problems mentioned in the Element modularity section explored earlier. Not only that but if you want to provide custom attributes for you new shiny view, you will have to deal with that in code. There is no way to define custom attributes using the properties inspector in the interface builder.
So, how does Android deal with this? Code-wise is the same thing, you extend the base view on which you pretend to add functionality. But the thing is that after you have created that view, you will be able to reference directly in the layout xml file, by naming the tag of the xml element to the fully qualified (java) name of the component you have just created. You can then create your own custom style definition, for example:
<declare-styleable name="RoundedImageView"> <attr format="dimension" name="radius"> </attr>
Then, you can use that new attribute in the view itself:
<com.example.views.RoundedImageView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:src="@drawable/magazine_header_bg" app:radius="2px" />
Then, you can load those custom attributes in the load method of your custom view (and of course, customize the draw call). On top of this, eclipse will be able to render your custom view with your custom attributes interpreted. Pretty nice.
Static elements are useful , but there comes a time when some interaction or some form of non-standard behavior is needed and you will need to reference your ui elements from the code.
I am going to be honest with you here, iOS takes the upper hand, since the ability to drag an element from the interface builder to the code file in order to automatically create a connected object is a pretty useful one.
In android you need to deal with all of the boilerplate code of inflating the root view, finding the children, etc. iOS is also pretty good at automatically binding an action on a element to a given method by dragging it to the implementation file. Once again on android you need to deal with setting on click listeners and whatnot.
Delivering your app in multiple languages in an extremely important matter. The tools you use to design your UI should help you easily localize the strings you use, and preview how the layout will look in multiple languages. Since most of the times you will be dealing with languages you don't understand you will need some way to send the strings to the translator.
In Xcode you have the option to localize a given .xib into multiple languages and preview how it will look in all the languages you have set as targets. It seems pretty good but it comes with some drawbacks. When you click the localize button, you are basically cloning your current xib.
This means that every change you make to you main xib will have to be manually propagated to all languages, making it a very tedious and error-prone process, specially when you just want to change the text of the elements.
Exporting a file that contains the strings needed to be translated is another pain, since your only option is to use the
ibtool and it has its own share of problems. The extraction process needs to be applied to all of the xibs, you end up with multiple files, the strings keys are strange, and you need to apply the reverse operation when you have the localized versions of the strings.
On the other hand, Android deals with this in a much cleaner and simpler way. Since all of your UI work is done inside a xml, every text-related attribute can be just a pointer to a string, subject to the same runtime resolve process as any other resource. By dividing your resources in multiple folders with the appropriate suffix, the OS will be able to select the appropriate resource when it needs it.
If you want to give the strings file for translation, just copy the values-XX folder (XX being the language) with the strings.xml inside to the translator.
One thing i would like to have in Eclipse was the option to change the string directly from the xml file that was using it. It would also be very nice to quickly get an overview of the string on all languages and to modify it without having to jump around between multiple files.
The ability to define animations in a simple-to-read way is very important. The advantage of having the animation declared in a separate file decoupled from the logic that will use it is also a nice feature to have.
Xcode has none of them, you have to declare animations in code, while having to deal with the verbosity of any cocoa framework, which can be really good in "normal" code but its just too much text to represent an animation.
Android deals with this by having the animations declared in a separate xml file that contains a larget set of customizable attributes allowing you to animate almost anything you want in a variety of ways. As far as I know, there is no way to animate a custom property of an object in iOS.
The good things about iOS development is that it's popularity brought a great deal of smart and determined developers to the scene that were able to quickly spot these problems and find solutions.
I will give just a very quick overview of what I was able to find that tackles the problems i mentioned earlier.
I haven't used most of them but they seem to be a good fit just by looking at their description.
Classy allows you to define the way your xib's will look in a CSS-like DSL. It also provides a Live Reload way of quickly seeing the effects of UI changes without having to recompile the app. Looks awesome.
Masonry deals with Auto-Layout. It really looks more expressive than the original system, but it would be great if we could define it in a separate file. For me Masonry is the HTML while Classy is the CSS. This blog post explains the use of both together.
AGi18n provides an easier way to deal with the localization pains.
Canvas deals manily with animation, providing a way to add properties in IB that will define what kind of animation to play, how long it should run, etc. These customization use the runtime attributes definition which has some obivous downsides of, once again, not being able to know what you can customize, what are the possible values and having to go to a submenu to see the animation values.
By now you may be thinking that i just wrote this to bash on Xcode while trying to glorify Android. That was not my intent. I really think that the iOS community deserves better, since the development environment is seriously lacking in regard to UI design.
I hope Apple will be able to improve this soon.