Thursday, November 4, 2010

Cupcake and Donut Compatibility Part I (The Invisible View Conundrum)

Android 1.5 (Cupcake) is a total nightmare to design for.  1.6 (Donut) is not a whole lot of fun either.  Fortunately, Cupcake has dropped to about 8% of the current Android population, and Donut is at 16%.  Unfortunately, to target Eclair, one is losing out on nearly a quarter of the possible users on the market.  Furthermore, since these users have almost no one releasing apps for them, they are more likely to use your app because it is their only option.

In Part I of the Compatibility series, I will demonstrate a work around for a disaster that happens one sets a View of a RelativeLayout invisible in Android 1.5

Now, suppose you three views in a RelativeLayout.  For example:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
android:id="@+id/TextView1"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="TextView1"
    />
<TextView  
android:id="@+id/TextView2"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="TextView2"
    android:layout_below="@id/TextView1"
    />
<TextView  
android:id="@+id/TextView3"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="TextView3"
    android:layout_below="@id/TextView2"
    />
</RelativeLayout>

This should look like




Now, suppose you want to set TextView2's visibility to View.GONE with

findViewById(R.id.TextView2).setVisibility(View.GONE);

Cupcake will give you this wonderful view:



Now, in subsequent versions of Android, this will show up like this:



The trick to get this sort of implementation in Cupcake is to wrap TextView2 in a descendant of ViewGroup, (AbsoluteLayout, LinearLayout, RelativeLayout, etc.).  The code below uses LinearLayout  to serve as a wrapper for the invisible TextView2.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
android:id="@+id/TextView1"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="TextView1"
    />
<LinearLayout
android:id="@+id/ViewGroup1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/TextView1">
<TextView  
android:id="@+id/TextView2"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="TextView2"
    />
</LinearLayout>
<TextView  
android:id="@+id/TextView3"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="TextView3"
    android:layout_below="@id/ViewGroup1"
    />
</RelativeLayout>

The problem exists because in Android 1.5, when TextView 2 is removed from the view, TextView3 is now asking the RelativeLayout to put it below a view that doesn't exist.  Thus, RelativeLayout, instead of crashing puts it in the default top-left corner.  In the code directly above, there is no view that references TextView2 to find it's layout.  ViewGroup1's height is set to wrap_content so when TextView2 disappears, ViewGroup1 no longer has any elements.  Thus, it collapses to 0px in height and TextView3 lies directly below TextView1.

This issue was corrected in Android 1.6.

No comments:

Post a Comment