Showing posts with label music player. Show all posts
Showing posts with label music player. Show all posts

Thursday, May 24, 2012

Android ImageView and BitmapDrawable: gravity and scaling to fit

This article explores whether it is possible to display a square picture (for instance the cover of a music album) in a way that it uses the whole width of the display and keeps its aspect ratio. No programming must be involved, i.e. a pure XML-layout definition is the goal.

The problem of proportional scaling

Milestone 1 of my journey into Android software development is creating a rudimentary GUI for a MP3 player app. On the way towards it I soon ran into a first problem, naturally. The cover image (in the mockup represented by compact disc) would not display as intended. It was supposed to fill the screen width, scaling proportionally in height (assuming square dimensions of the cover and portrait orientation of the phone). And though the BitmapDrawable scaled (down) correctly, the enclosing ImageView would never wrap it up in height. In fact, it would be so large that it even pushed the SeekBar out of screen:


Dream (left) and reality (right): the ImageView does not adjust its height to the picture of the compact disc. Its actual dimensions are marked by the blue border!
My first attempt to layout the ImageView is shown by the following code snippet. The cover image sits inside a RelativeLayout (not shown) and is aligned below the song title (line 5).

<ImageView  
       android:id="@+id/cover"  
       android:layout_width="match_parent"  
       android:layout_height="wrap_content"  
       android:layout_below="@id/songtitle"  
       android:src="@drawable/cd" />  

I assumed that setting layout_width to to «match_parent» would scale the image to fit in width, which it seemed to do. Furthermore I assumed that setting layout_height to «wrap_content» would shrink the view closely wrap the image, i.e. would result in a ImageView of square proportion. It did not, obviously.

I am not going to retrace in detail how I went trial-and-error through the numerous properties of the Drawable and ImageView classes. Lets approach it more systematically, because there is more than a single factor in effect here. The source code for this project is available at GitHub. I will created tags for each point discussed in this blog.

For this experiment, I created three square images of varying dimensions: one too small for a WVGA800 screen (which is 480×800px in the case of the Galaxy S2), it is 100 pixel wide and tall; another of exact fit (480px wide); and a third images too large for the screen (800px wide). The vanilla layout looks like this for these three image sizes:

Android prevents clipping of over-sized images and rather scales them down. The blue border marks the bounds of the ImageView.
Only for the picture which is too small for the screen the ImageView behaves as expected (by me, at least). For both the exact fit and the over-sized picture the ImageView does not wrap its content. Android also scales down the over-sized picture to fit the screen, which is a sensible precaution. The small image however is not enlarged automatically, probably because it a) might look terrible, b) does no harm to leave it as is.
Now lets play with the properties of the user interface components.

BitmapDrawable gravity (and tiling)

Poking around the API documentation, I first stumbled upon the gravity attribute of the BitmapDrawable class. It looked promising, offering options for pushing a picture toward any edge of the container, or scaling it, or clipping it. Surprisingly, none of the options had any effect on the scaling and placement of the sample images from above. For both of the larger images the API documentation might explain:
The gravity indicates where to position the drawable in its container if the bitmap is smaller than the container.
But why then does it not work for the small image either? It turned out, that the phrase «in its container» misled me. The source code of BitmapDrawable.draw(Canvas) reveals that gravity only applies within the bounds of the BitmapDrawable itself. The ImageView sets these bounds via Drawable.setBounds(int,int,int,int) to the exact dimension of the underlying bitmap image. There is only one case in which the bounds actually matches the proportion of the ImageView and this is when ImageView.scaleType==FIT_XY («fitXY» in a XML-layout) in the private method ImageView.configureBounds().

The scaleType of class ImageView defaults to «FIT_CENTER». To make use of gravity, it must be set to «fitXY». Furthermore the src-property of the ImageView must refer to a bitmap XML-definition and not to an image file (res/layout/toosmall.xml):

<ImageView
    android:id="@+id/cover"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/songtitle"
    android:scaleType="fitXY"
    android:src="@drawable/toosmall" />

Then the gravity of the BitmapDrawable can be configured with something like this (res/drawable/toosmall.xml):

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/square100"
    android:gravity="fill_vertical"
/>

That means gravity only affects the appearance of the picture if the bounds of the Drawable are actually larger than the physical dimension of the picture displayed. Apart from ImageViews with ScaleType.FIT_XY this is the case for View backgrounds. Best use an empty, fully expanded LinearLayout for experiment, as I did for the following screenshot.

As background image, a DrawableBitmap receives enough room for gravity and tiling to have an effect. From left to right: gravity="right|center_vertical", gravity="fill_vertical", tileMode="mirror".
The gravity property has further oddities. Especially the properties clip_vertical and clip_horizontal behave completely opposite to intuition as +Lorne Laliberte points out.

ImageView scaleType and adjustViewBounds

The scaleType has a major say on the placement of a Drawable inside an ImageView (read the Andre Steingress' blog posting on its various effects). But disabling scaling via «fitXY» in order to make gravity take effect will not solve the problem of the view area being larger than the contained bitmap! No combination of gravity flags will scale the bitmap proportionally! So gravity was a red herring after all. It is the property «adjustViewBounds» in combination with the default scaleType that will do the job.
[Update 2012-05-25]: When adjustViewBounds is true, the scaleType no longer matters: ImageView will reset it to FIT_CENTER (the default) anyway.

The adjustViewBounds property will shrink the ImageView to fit its content. it has unwanted side-effects, though.
Now cry «cheat!» The larger images look fine, but the small image stubbornly retains it dimensions, and is not scaled to fill the width of the screen. Unfortunately, there seems to be no way to fix this by a XML-layout definition alone, programming is required, and I am defeated for now. I will explore the different approaches in a later posting.
If someone knows a way to archive it by pure XML, I would be grateful to hear about it!

Conclusion

There seems to be no way to proportionally scale an ImageView to match its parents width by means of a XML-layout definition alone. Bitmaps which are larger than the available display space will be reduced in size correctly but smaller images never enlarge proportionally. The most obvious solution would be to provide fitting or over-sized bitmap images for each targeted device. But this is neither future-proof nor always possible—think of the cover images which usually come in just one size, attached to a MP3-file. But then again, dynamically loading images always requires some programming anyway. So a few extra lines of code might not matter too much.

Thursday, May 10, 2012

Free Android mockup tools for Linux users

There is a wealth of drawing tools available that can be used for mocking up user interfaces. On Stackoverflow you can find a comprehensive collection of tools for prototyping Android and iOS interfaces. There are web-apps and desktop applications on the list, some free, but most are commercial products. SocialCompare has a «Mockup and Wireframing Design Tools comparison» which also includes pricing.
This article takes a glimpse on prototyping applications that are both free to use and work under Linux.

All-purpose tools

In the end almost any drawing tool will do for drawing a mockup, be it a vector drawing tool like the commercial Adobe Freehand or the free and open source Inkscape, be it a classical bitmap drawing application like Adobe Photoshop or the free and open source GIMP, or be it a diagramming software like Microsoft Visio or Omnigroups Omnigraffle; even presentation programs like LibreOffice Impress will do. Browsing a a software directories like alternativeTo will explode this list.

Prototyping with GIMP
Layering is the way to arrange user interface elements with the GIMP.

The catch with these all-purpose application is that their learning curve is quite steep and that they usually lack templates for prototyping. Enter dedicated mockup applications. These tools dispose of every option and function not needed for prototyping, plus provide ready made sets of user interface elements.

From the aforementioned list on the Stackoverflow I only tried standalone application or web applications that a) seemed suitable for Android prototyping, b) appeared to be not too heavy weight in either download size and functionality, c) come free of charge (though maybe crippled), and d) run under Linux. Hence the following text covers only a small fraction of applications available on the market. More can be found at KONIGI, for instance.

Mockingbird

The web application Mockingbird strives for simplicity in every aspect. The functionality is trimmed down to the functions essential for layout: stacking, aligning, and grouping, plus tuning some properties of the interface elements. As you can see in the screenshot below, the interface templates look clear and minimalist. I liked that. There are no platform specific controls available, consequently. Navigation between individual screens can be establish through hyperlinks. Multiple users can share a project.
Mockingbird does not require a Flash player.

It only takes a few minutes to sketch a user interface with applications like Mockingbird.

The one thing I liked best about Mockingbird was the on-the-fly alignment feature. When you drag an object around, Mockingbrid will create guiding lines to all the neighboring elements. I never needed the alignment menu to spread out the controls of my mockup. Quite a few applications (in fact all in this article except Yeblon ) offer such guides, but Mockingbird's implementations works particularly well.

Mockingbird's guiding lines make the alignment menu unnecessary.

Mockingbird is a freemium service. Free users are limited to a single project and one collaborator.

iPlotz

The next contestant, iPlotz, is also freemium web service. Free users are barred from collaborative mockup editing, but are otherwise pretty unrestricted. This makes iPlotz a great choice for solitary developers.
There is a desktop application available for sale. It is implemented in Adobe Air and should run on all major platforms.

The drawing tool of iPlotz offers many professional features.

IPlotz offers much more features than Mockingbird, many of which will appeal to professional designers, for instance page masters, layers, and data sources (tables) that can be connected to various user interface elements. The template library of iPlotz leaves nothing to be desired. It also includes user interface elements for Android and the iPhone, though the style of the Android controls is rather antique. If the template library  does not contain an element needed, the user can compensate by drawing polygon shapes, lines, or importing bitmap graphics. Interface elements can be linked to other pages of the design or the WWW to simulate page flow.

iPlotz also includes project management features.
In addition to mockup drawing, iPlotz offers some project management features. The user can manage multiple projects, add collaborators, and assign task to them.

Yeblon

Yeblon comes free of charge, but is really no more than a toy. Simplicity is one thing, but Yeblon is barren featurewise. The most fundamental flaw being that the text on the very limited set of templates cannot be changed. This forces the user to choose simple text over specific controls. After all, what is the use of having three buttons on a mockup all named «label»?

Yeblon is not suitable for mockup drawing, or anything.

Grouping and aligning of objects is not possible, there are no collaboration features. Every saving of the design yields a publicly accessible URL, which is neat for sharing. The file however is referenced by a sequential number within the URL (mine was only 1968—so much for popularity), which means no privacy. Randomly picking a few layouts other users made, it became pretty clear how the typical Yeblon use-case looks like: try to draw something, fail, leave and never come back. I recommend skipping the first three steps.

MockFlow

MockFlow is the last of the web applications I tested. Just like iPlotz it was made with Adobe Air and a desktop application is available. Free-of-charge usage is possible, but MockFlow places more restrictions on free users than iPlotz. Especially the limitation to only a single project with a maximum of four pages hurts.

MockFlow offers only basic layout function, but the library really shines.

Anyone who tried one of the aforementioned applications will immediately feel at home with the drawing view of MockFlow. It sports a template library on the right from which the user drags the desired user interface elements onto the canvas. Grouping and alignment works as expected. The library is well equipped. Additional components can be added from the «MockStore». It includes a complete set of user interface component of the Android 4.0 Holo theme. It would be even better if one could change the color of the included icons.
I did not try any of the online collaboration features. But for every project a public URL can be created, which is really nice. Unlike Yeblon, the public URL cannot be guessed.

The most severe flaw of MockFlow is its sluggishness. Placing user interface elements was almost impossible. It felt like drawing the object through tar. I tried Firefox and Chromium. Unless this is fixed, MockFlow is no competition for iPlotz or Mockingbird.

Pencil

Finally, with Pencil there is a contestant that is not a web app. It is actually an add-on for the Firefox web-browser, but can be run as a stand-alone application via the xulrunner. On my Fedora 16 desktop this latter way was blocked because the application package was outdated. There are ways around this, but they are cumbersome. Pencil is the only free and open source application on this list.

Again Pencil looks pretty much as all its competitors. Its library contains all the fundamental components for user interface design. Android templates must be imported. Simple generic polygon shapes can be drawn and images imported. The appearance of most components can be adjusted in much detail.

Pencil is a free and open source application build on top of Firefox.

Alignment and re-sizing did not work as smooth as with the competitors. Collection management is rather painful. Page flow can be established by links on any component, though the option to create them only appears when there actually are multiple pages. Pencil implements—not surprisingly—no online collaboration features.

I cannot withhold a final rant, that is not altogether related to Pencil: Implementing any application that is not internet-related as a browser add-on is just sick. It is even worse than the other scourge of humanity discussed here: the web application. The latter is also a perversion (though a useful one) because it abuses the web browser for what it was never meant to be: an operation system; the biggest pimps of this ill fad being Google and as of late Mozilla. Web applications at least may offer some collaboration features and are ready at your fingertips. But what benefits does an implementation as a browser add-on bring? It only makes one of the greediest memory hogs on a desktop system fatter—Firefox that is!

Conclusion

There seems to be a pattern inherent to GUI prototyping applications. If you know one you know them all. If I, as a solitary developer who wants to invest not a single dime, would have to pick from the list above, I probably would go for either iPlotz or Pencil. The former because of its feature richness, its fully equipped library of GUI components, and because it places the fewest restrictions on free riders. Pencil feels not quite as professional as iPlotz, but is has the FLOSS bonus. Third place goes to Mockingbird, which I really liked for its minimalist approach and ease of use. It would rank better would its free plan not be so restrictive. MockFlow could compete with iPlotz if it was not plagued by sluggishness, check it out for yourself, if it works smooth enough for you. Yeblon is really just a toy.

[Changelog]

2012-05-14: Added a link to a comparison of mockup tools at SocialCompare.

Tuesday, May 8, 2012

Developing mobile apps—getting started

During the next couple of weeks I am going to dive into mobile app development. The Android platform will be my starting point for the simple reason that I own an Android phone. My first app will be a simple MP3 player, just like the one that ships with every phone. It is not very ingenious, I admit it, but for the educational purpose it is okay. And actually, there is an itch I need to scratch with the players I have tried so far (and certainly with the default player). But more on this later.

The educational milestones for the immediate future are:

  1. Build working but non-functional user interface for the main view of the music player. This will unveil how difficult it is to build a simple user interface on the platform.
  2. Add basic media player functionality, like starting, stopping, and pausing the playback, skipping tracks, and so on. This will show how to interact with a system service (which media playback hopefully is) and how to perform background tasks.
  3. Add more views for selecting media files by album, artist, and genre. This will introduce some of the more complex user interface controls. Passing to an fro between the different views will be required, and maybe some metadata scavenging also.
  4. Trigger player functionality by gestures, for instance wiping the screen from left to right for skipping to the next title on the play list. This will teach me about gestures, obviously.
  5. Add bells and whistles, meaning: animation. Mobile devices often sport playful user interfaces. Some provide valuable feedback to the user, other are merely showing off. Performing gestures without animation might be awkward, so this milestone might get a promotion.
  6. Turn the player into something useful.

After I made some  progress though this list with the Android app, another OS will join the circus. That should be when I reach milestone 3. The next OS will be either Windows Mobile or Samsung's Bada. The former because phones for that platform are comparatively cheap, the latter because my wife owns a Bada phone. The third OS will be iOS, alas.