Tuesday, July 5, 2011

Custom Tabs that Scroll Horizontally

So I designed horizontally scrolling tabs that use separate activities to fill the tab content. TI rate this a 1/5 on the fun scale: there are so many different files you have to create and different selection states you have to consider. (Click here for my update to this tutorial: Changing Tab with Horizontal Swipe Gesture)

Faded edges indicate additional content
tabhostlayout.xml - Pretty basic stuff here, if you followed the tab widget tutorial on the android dev site.[1] The only thing to note here is that I surrounded the tab widget with Horizontal Scroll View element to achieve a horizontal scroll for the tabs. (Note: Sorry for the formatting here. I've tried to fix it only to make it much much worse. Blame blogger?)
<TabHost
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@android:id/tabhost"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent">
<LinearLayout
          android:orientation="vertical"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent">
<HorizontalScrollView
               android:layout_width="fill_parent"
               android:layout_height="wrap_content">
                <TabWidget
                    android:id="@android:id/tabs"
                   android:layout_width="fill_parent"
                    android:layout_height="wrap_content" />
</HorizontalScrollView>
<FrameLayout
               android:id="@android:id/tabcontent"
               android:layout_width="fill_parent"
               android:layout_height="fill_parent"
               android:padding="5dp" />
</LinearLayout>
</TabHost>

TabHostActivity.java - This activity must extend TabActivity. You will need to define the following variables and also set the divider drawable BEFORE setting up tabs

TabHost mTabHost = (TabHost) findViewById(android.R.id.tabhost);
mTabHost.getTabWidget().setDividerDrawable(R.drawable.tab_divider);
Intent intent; // Reusable Intent for each tab

For each tab you would like to add, use the following code in onCreate:
intent = new Intent().setClass(TabHostActivity.this, PageOne.class);
setupTab(new TextView(this), "Tab One", intent);

After onCreate, you need to add two new classes. "setupTab" creates the tabs and tab content. "createTabView" handles all tab events, like setting the views for selection events and stuff like that.
private void setupTab(final View view, final String tag, final Intent myIntent) {
View tabview = createTabView(mTabHost.getContext(), tag);
TabSpec setContent = mTabHost.newTabSpec(tag).setIndicator(tabview).setContent(myIntent);
mTabHost.addTab(setContent);
}
private static View createTabView(final Context context, final String text) {
View view = LayoutInflater.from(context).inflate(R.layout.tabs_bg, null);
TextView tv = (TextView) view.findViewById(R.id.tabsText);
tv.setText(text);
return view;
}

tabs_bg.xml - In the code above, "createTabView" calls a layout called tabs_bg. Create this file in the layout folder. This layout creates the layout for each tab element. I have only added a single textview but an image view could also be added (but will need some adjustments to the java code not shown above). This is where some of the layout personalization comes in. Text size and style, and padding elements. Note the background and text color call drawable files that handle the color changes for selection events.
<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/tabsLayout"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:background="@drawable/tab_bg_selector"
     android:padding="3dip"
     android:gravity="center"
     android:orientation="vertical">
<TextView
          android:layout_width="wrap_content"
          android:textColor="@drawable/tab_text_selector"
          android:gravity="center"
          android:textSize="12dip"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:id="@+id/tabsText"
          android:text="Title"
          android:padding="10px">
</TextView>
</LinearLayout>

tab_bg_selector.xml - both bg and text selector drawable files require the same four states to be defined: active, pressed, selected (using arrows), and inactive. I don't really know why the text and bg have to be separate files, but when I tried to combine them, it wasn't displaying properly. This code resembles custom button selection.
<selector
     xmlns:android="http://schemas.android.com/apk/res/android">
     <!--  Active tab -->
   
<item
          android:state_selected="true"
          android:state_focused="false"
          android:state_pressed="false">
          <shape
               android:shape="rectangle">
               <gradient
                    android:startColor="#A8A8A8"
                    android:centerColor="#7F7F7F"
                    android:endColor="#696969"
                    android:angle="-90" />
          </shape>
     </item>
   
<!--  Inactive tab -->
   
<item
          android:state_selected="false"
          android:state_focused="false"
          android:state_pressed="false">
          <shape
               android:shape="rectangle">
               <gradient
                    android:startColor="#5C5C5C"
                    android:centerColor="#424242"
                    android:endColor="#222222"
                    android:angle="-90" />
          </shape>
     </item>
<!--  Pressed tab -->
<item
          android:state_pressed="true"
          android:drawable="@android:color/transparent" />
<!--  Selected tab (using d-pad) -->
 <item
          android:state_selected="true"
          android:state_focused="true"
          android:state_pressed="false"
          android:drawable="@android:color/transparent" />
</selector>

tab_text_selector.xml
<selector
     xmlns:android="http://schemas.android.com/apk/res/android">
     <item
          android:state_selected="true"
          android:color="@android:color/white" />
<item
          android:state_focused="true"
          android:color="@android:color/white" />
<item
          android:state_pressed="true"
          android:color="@android:color/white" />
   
<item
          android:color="#f8f8f8" />
</selector>

References:
1) http://developer.android.com/resources/tutorials/views/hello-tabwidget.html
2)http://joshclemm.com/blog/?p=136
For additional help, click here to download a zip containing all the files needed to create the above project.

Friday, July 1, 2011

Solution to "Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE"

Source: http://stackoverflow.com/questions/4709137/solution-android-install-failed-insufficient-storage-error


Getting this error: 

[2011-07-01 10:36:22 - MDatHand] Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE
[2011-07-01 10:36:22 - MDatHand] Please check logcat output for more details.
[2011-07-01 10:36:22 - MDatHand] Launch canceled!


I used this solution:


RIGHT CLICK the root of your Android Project
SELECT "Run As" then go to "Run Configurations..." 
LOCATE the "Android Application" node in the tree at the left then SELECT your project
SELECT "Target" tab on the right side of the window look down for the "Additional Emulator Command Line Options" field (sometimes you'll need to make the window larger) 
PASTE "-partition-size 1024" there
CLICK "Apply" and then Run to use your emulator
Like so.