B4A Library TabHostExtras

Here is a new library i have created that allows you to customise a TabHost.

TabHostExtras
Version: 2.2
  • TabHostExtras
    Methods:
    • GetTagWidget (TabHost1 As TabHost) As TabWidget
      Returns TabHost1's TabWidget.
      Allowing you to customize various settings.
    • getTabContentViewPadding (tabHost1 As TabHost) As RectWrapper
      Get the layout padding of tabHost1 TabContentView
      Returns a Rect object containing pixel values
    • getTabEnabled (tabHost1 As TabHost, index As Int) As Boolean
      Get the Enabled state of TabIndicator #index in tabHost1
    • getTabHeight (tabHost1 As TabHost) As Int
      Get the height (in pixels) of the TabIndicators in tabHost1
    • getTabHostPadding (tabHost1 As TabHost) As RectWrapper
      Get the layout padding of tabHost1 container View
      Returns a Rect object containing pixel values
    • getTabIcon (tabHost1 As TabHost, TabIndex As Int) As ImageViewWrapper
      Get the (icon) ImageView of TabIndicator #TabIndex in tabHost1
    • getTabTextSize (tabHost1 As TabHost) As Float
      Get the text size (in pixels) of all TabIndicators
    • getTabVisibility (tabHost1 As TabHost, index As Int) As Boolean
      Get the visibility of TabIndicators #index in tabHost1
    • setTabContentViewPadding (tabHost1 As TabHost, left As Int, top As Int, right As Int, bottom As Int)
      Set the layout padding (in dip) of tabHost1 TabContentView
    • setTabEnabled (tabHost1 As TabHost, enabled As Boolean)
      Enable or disable all TabIndicators in tabHost1
    • setTabEnabled2 (tabHost1 As TabHost, enabled As Boolean, index As Int)
      Enable or disable TabIndicator #index in tabHost1
    • setTabGradientDrawable (tabHost1 As TabHost, orientation As String, color1 As Int, color2 As Int, cornerRadius As Float)
      Set a GradientDrawable as the background on all TabIndicators in tabHost1
      All fours corner radii of the GradientDrawable are set to the value of cornerRadius (in pixels)
    • setTabGradientDrawable2 (tabHost1 As TabHost, orientation As String, color1 As Int, color2 As Int, cornerRadius() As Float)
      Set a GradientDrawable as the background on all TabIndicators in tabHost1
      Corner radii of the GradientDrawable are set individually (in pixels) based upon the number of elements in the array cornerRadius:
      1 element defines all corner radii
      2 elements define corner radii in order top left and right, bottom left and right
      4 elements define corner radii in order top-left, top-right, bottom-right, bottom-left
    • setTabHeight (tabHost1 As TabHost, tabHeight As Int)
      Set the height (in pixels) of all TabIndicators in tabHost1
    • setTabHostPadding (tabHost1 As TabHost, left As Int, top As Int, right As Int, bottom As Int)
      Set the layout padding (in dip) of tabHost1 container View
    • setTabTextColor (tabHost1 As TabHost, Color As Int)
      Set the color to be used for all tab indicators text.
      This color will be used for all tab indicators regardless of their selected state.
    • setTabTextColorStateList (tabHost1 As TabHost, ColorStateListName As String)
      Set a ColorStateList to be used for the text color of all tab indicators.
      The ColorStateList must be defined in XML in your application Objects/res/drawable folder.
      Color for selected and not selected tab state can be defined.
    • setTabTextSize (tabHost1 As TabHost, TextSize As Float)
      Set the text size of all TabIndicators
      TextSize is assumed to be in units of dip.
    • setTabTitle (tabHost1 As TabHost, Title As String, TabIndex As Int)
      Set the Title text of TabIndicator #TabIndex in tabHost1
    • setTabVisibility (tabHost1 As TabHost, visible As Boolean)
      Set the visibility of all TabIndicators in tabHost1
    • setTabVisibility2 (tabHost1 As TabHost, visible As Boolean, index As Int)
      Set the visibility of TabIndicator #index in tabHost1
  • TabWidget
    Methods:
    • BringToFront
    • GetChildTabViewAt (TabIndex As Int) As View
      Returns the tab indicator view at the given index.
      The returned View will be a ViewGroup with 2 child Views:
      An ImageView at index 0 and a TextView at Index 1.
    • GetTabIcon (TabIndex As Int) As ImageViewWrapper
      Get the (icon) ImageView of the tab indicator view at the given index.
    • GetTabLabel (TabIndex As Int) As LabelWrapper
      Get the (TextView) Label of the tab indicator view at the given index.
    • Initialize (arg1 As String)
    • Invalidate
    • Invalidate2 (arg0 As Rect)
    • Invalidate3 (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
    • IsInitialized As Boolean
    • RemoveView
    • RequestFocus As Boolean
    • SendToBack
    • SetBackgroundImage (arg0 As Bitmap)
    • SetLayout (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
    Properties:
    • Background As Drawable
    • Color As Int [write only]
    • DividerDrawable As Drawable [write only]
      Sets the drawable to use as a divider between the tab indicators.
    • Enabled As Boolean
      Get or Set the enabled state of the TabWidget.
    • Height As Int
    • Left As Int
    • LeftStripDrawable As Drawable [write only]
      Sets the drawable to use as the left part of the strip below the tab indicators.
    • RightStripDrawable As Drawable [write only]
      Sets the drawable to use as the right part of the strip below the tab indicators.
    • StripEnabled As Boolean
      Get or Set whether the bottom strips on the tab indicators are drawn or not.
    • TabCount As Int [read only]
      Get the number of tab indicator views.
    • Tag As Object
    • Top As Int
    • Visible As Boolean
    • Width As Int

Attached are the library files and a little demo.
If you run the demo try your device's 'Menu' key and toggle the tabs from visible to hidden.

I originally created this functionality in a code module and once it was working created the library.
So i have attached the code module as a separate attachment in case anyone wants to use it - the Reflection library is required if you use the code module but is not required if you use the library of course.

The code module has a Sub (not included in the library):

GetTabIndicators(TabHost1 As TabHost) As View()

This will return an array of Views, these Views are the TabHost's TabIndicators.
Anyone hoping to further customise the look of a TabHost may find this Sub useful - see the code module demo for an example of changing the TabIndicators' Color property.

Martin.
 

Attachments

  • TabHostExtrasCodeModule.zip
    8.9 KB · Views: 2,076
  • TabHostExtras_v2_20.zip
    22 KB · Views: 2,912
Last edited:

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Very useful library. I used it to help out with a layout problem I had, although not the way I wanted to. I ended up just setting my paddings to 0 so I can get the tabhost Tab Height and know what my content area size is then. A few suggestions for 1.8:

1. A way to get the padding values. Then I can use them in calculations to figure out the size of the content area.

2. A color array for the gradient. By the documentation I assumed only two colors too, but I made a function for my buttons lately that I use a color array and pass 3 colors which looks really nice. I'm not sure what the limit is, but it allows for more variations than I expected.

How did you pick which corners to apply a radius to? I'd like to make some buttons like that with diaganol corners rounded and not rounded.

3. Is it possible for individual Tab Colors where each tab is a different color or gradient?
 

warwound

Expert
Licensed User
Longtime User
TabHostExtras updated to version 1.80

Two new methods have been added:

getTabContentViewPadding (tabHost1 As TabHost) As Rect

Get the layout padding of tabHost1 TabContentView
Returns a Rect object containing pixel values

getTabHostPadding (tabHost1 As TabHost) As Rect

Get the layout padding of tabHost1 container View
Returns a Rect object containing pixel values

Documentation for the Rect object can be found here: Basic4android - Drawing (Core).

Version 1.80 is attached to the first post in this thread.

Martin.
 

warwound

Expert
Licensed User
Longtime User
2. A color array for the gradient. By the documentation I assumed only two colors too, but I made a function for my buttons lately that I use a color array and pass 3 colors which looks really nice. I'm not sure what the limit is, but it allows for more variations than I expected.

How did you pick which corners to apply a radius to? I'd like to make some buttons like that with diaganol corners rounded and not rounded.

I'm not sure about creating gradients with more than two colors - can you post your function so i can see how you have done it?

Look at the documentation for the native Android GradientDrawable and it's setCornerRadii and setCornerRadius methods.
These are the two methods i've used in TabHostExtras.

3. Is it possible for individual Tab Colors where each tab is a different color or gradient?

Here's the source code for the setTabGradientDrawable method:

B4X:
   /**
    * Set a GradientDrawable as the background on all TabIndicators in tabHost1
    * All fours corner radii of the GradientDrawable are set to the value of cornerRadius (in pixels)
    */
   public static void setTabGradientDrawable(TabHost tabHost1, String orientation, int color1, int color2, float cornerRadius) {
      GradientDrawable gradientDrawable1 = new GradientDrawable(GradientDrawable.Orientation.valueOf(orientation), new int[] { color1, color2 });
      gradientDrawable1.setCornerRadius(cornerRadius);
      TabWidget tabWidget1 = tabHost1.getTabWidget();
      int tabCount = tabWidget1.getChildCount();
      while (tabCount-- > 0) {
         tabWidget1.getChildAt(tabCount).setBackgroundDrawable(gradientDrawable1);
      }
   }

You can see that it applies the same GradientDrawable to each tab.
There's no reason why you couldn't apply a different GradientDrawable to each tab.

tabWidget1.getChildAt(tabCount) is a RelativeLayout.
So you can use any RelativeLayout methods, or methods that RelativeLayout inherits from it's super class, to manipulate it's visual style.

The problem with updating the tabs with GradientDrawables has been mentioned before in this thread, see http://www.b4x.com/forum/additional-libraries-official-updates/11056-tabhostextras-3.html#post79561.

I could create two new methods setTabGradientDrawable3 and setTabGradientDrawable4 which would function the same as setTabGradientDrawable and setTabGradientDrawable2 BUT only apply the GradientDrawable to a single tab referenced by it's index.

I don't have time for that today but will put it on my list of things to do!

Martin.
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Cool. No rush on the individual tab color stuff...my current app I imagine will take a while as it is very large and I can always add the tab colors later. The other stuff was great though and quick. I got an email last night about the 1.80 post and was amazed at the speed. I'll play with it today and add my padding back now. I like Putting them in a Rect vs all the int values too. When I first read the post I was thinking it was the actual Rect on the screen which would have been interesting to use for drawing on it, but they appear to just hold the pad values for that side. How are the CenterX and CenterY used here? Is CenterX an average of Right and Left and CenterY of Tob/Bottom?

The button gradient code I mentioned I actually put here already- http://www.b4x.com/forum/basic4andr...589-statelistdrawable-example.html#post102383

I use just two in the example, but I was playing yesterday trying to make a gel button with 4-5 colors. I wish the button allowed a color and a gradient on top of it without resorting to other drawing on the button. It could make a cool looking button using a static color with a white/black/transparent gradient overlay.
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Looks like some of what you said in post #27 is applying to my tabs. Android Tabs aren't the best...In pictures I see nice tabs with an image and text below it, and from the default margin they give I'd expect this. Unfortunately my image even when sized 16x16 all the way up to 48x48 using LoadBitmapSample takes up the whole tab. This then is drawn over by white or grey text with no shadows or outlines or anything to make it blend better.

So, I tried setting the font size with hopes of a bigger font being easier to read, but I've tried sizes all the way up to 120 and the font of the tabs don't change. I've tried making the tabs taller too in hopes of it allowing the image to shift up. It doesn't draw any different, but does appear to set its value since I use it to size my panels and they shift smaller. Erel may need to make some of this stuff an option in the view for it to work.

These last couple weeks I'm starting to wonder how anyone gets apps made for Android spending 70% of my time trying to figure out work arounds for Android's odd behaviors. Looks like I'm going to have to make my images contain the text for now...which won't look as crisp.
 

salmander

Active Member
Licensed User
Longtime User
When using Android 4.0 Layout, by changing the manifest to;
B4X:
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14" />
The following line gives an error.
B4X:
TabHostManager.setTabTitle(TabHost1, "--VEHICLE INFO--", 0)

B4X:
search_showresults (B4A line: 846)


TabHostManager.setTabTitle(TabHost1, "--VEHICLE INFO--", 0)

java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.RelativeLayout
   at uk.co.martinpearman.b4a.tabhostextras.TabHostExtras.setTabTitle(TabHostExtras.java:192)
   at com.home.cafiq.test.search._showresults(search.java:4997)
   at com.home.cafiq.test.search._searchjob(search.java:4942)
   at com.home.cafiq.test.search._jobdone(search.java:3499)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
   at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:793)
   at anywheresoftware.b4a.keywords.Common.CallSub2(Common.java:780)
   at com.home.cafiq.test.httputilsservice._processnexttask(httputilsservice.java:256)
   at com.home.cafiq.test.httputilsservice._response_streamfinish(httputilsservice.java:357)
   at java.lang.reflect.Method.invokeNative(Native Method)


   at java.lang.reflect.Method.invoke(Method.java:511)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
   at anywheresoftware.b4a.BA$3.run(BA.java:296)
   at android.os.Handler.handleCallback(Handler.java:607)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:156)
   at android.app.ActivityThread.main(ActivityThread.java:5005)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
   at dalvik.system.NativeStart.main(Native Method)
java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.RelativeLayout
 

warwound

Expert
Licensed User
Longtime User
TabHostExtras updated to version 1.90

Hi.

Sorry for the delay in replying.

I don't have an ICS device to test on but used the emulator - API level 15.

I ran the demo code on a Gingerbread device and the ICS emulator and used the SDK tool Hierarchy Viewer to inspect the TabHost.

I suspected that with ICS a change had been made and ICS used a LinearLayout where previous versions used a RelativeLayout - that would explain the exception you posted.

But there is no change, the clickable Tabs are RelativeLayouts in both Gingerbread and ICS.
The demo code also runs with no problems on the emulator, using the Menu option Change title calls the TabHostExtras setTabTitle method and it works with no exceptions.

Then i updated the manifest, adding:

B4X:
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14" />

And the exception is now raised.
Hierarchy Viewer now shows what i first thought - ICS is using a LinearLayout where previous versions used a RelativeLayout but only with that manifest edit.

Both LinearLayout and RelativeLayout are of type ViewGroup so a little update to the library code seems to have fixed everything.

Version 1.90 is attached to the first post in this thread.

Martin.
 

salmander

Active Member
Licensed User
Longtime User
Thank you very much mate. I am searching the forum to change the color of the tab indicator text. Is it not supported yet?
 

warwound

Expert
Licensed User
Longtime User
Thank you very much mate. I am searching the forum to change the color of the tab indicator text. Is it not supported yet?

Look back to this thread: http://www.b4x.com/forum/additional...-updates/11056-tabhostextras-4.html#post90535

The tab indicator text is displayed using an Android TextView so in theory it'd be quick and easy to add a method to change the text color of one or all tab indicators.

But tabs indicators have different states: active tab/inactive tab for example.

So you need to set a ColorStateList to define the text colors to use.

If ColorListState had already been wrapped within the B4A IDE so you could create a ColorListState in B4A then it is again simple to write a method to apply a ColorListState to one or more tab indicators.

But the ColorListState is not available within the B4A IDE so adding the ability to set tab indicator colors would mean creating a B4A wrapper class around the android ColorListState class as well as creating the required setter method.

I do not have time to create such a wrapper class unfortunately.

But thinking about it - maybe there's a simpler way...

Look here: Color State List Resource | Android Developers

You can create a ColorListArray purely in XML, make that XML file read-only and then TabHostExtras would require just a simple setter method to apply that ColorListState to a tab indicator....

I've made a note to do some research (tomorrow morning i think) and will post again.

Martin.
 

salmander

Active Member
Licensed User
Longtime User
That is very helpful of you. I am looking forward for it. But, in mean time, can I change the color of the text of all the tab indicator using reflection library please(tab state doesn't matter at the moment as my tabhost is transparent and the background of the activity is Gray colored image so the default color (white) is un-readable)?
 

warwound

Expert
Licensed User
Longtime User
Try the attached alpha version i've just compiled.

The use of a ColorListState defined in XML doesn't seem to work, that's the new setTabTextColor2 method.

But a quick test of the setTabTextColor method worked ok on my ZTE Blade.
The same color being displayed no matter what the state of the tab indicator:

B4X:
TabManager.setTabTextColor(TabHost1, Colors.Red)

Did you want all tab indicators to have the same text color?

I'll try and get the XML stuff working and post again.

Martin.
 
Last edited:

salmander

Active Member
Licensed User
Longtime User
Ohh wow That was quick...thanks a lot mate...I will test it and post my findings...

Actually, I have an activity with a background image which is basically light gray colored image. The activity contains a Tabhost with colors.transparent value. When I implemented the Android 4.0 layout (as described by Erel), the tab indicator also became transparent and thus the default color of the text indicator text (which is white) was un-readable. That is why I asked you, if it is possible to change the text color of the tabhost tab indicator to something like black while you are working on changing the textcolor StateList way. Thanks a lot again. I am testing it right now and will update you once tested.
 

warwound

Expert
Licensed User
Longtime User
TabHostExtras updated to version 2.00

At last you can set the color of the text in your tab indicators!

This update adds two new methods:

setTabTextColor

setTabTextColorStateList

Check out the first post in this thread for method syntax, usage notes and and the new library version download.

setTabTextColorStateList is probably the most useful of these two new methods, you can define a ColorStateList using XML and set that as the color to be used for the tab indicators:

B4X:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_selected="true"   
      android:color="#0000FF" />
   <item android:state_selected="false"   
      android:color="#FF0000" />
</selector>

Here a selected tab indicator's text is blue, an unselected tab indicator's text is red.
The attachement in post #1 contains this example XML file.
Assuming that your XML file is named tab_widget_text_colors.xml, you set this ColorStateList as tab indicator text color:

B4X:
TabManager.setTabTextColorStateList(TabHost1, "tab_widget_text_colors")

The ColorStateListName being the XML filename without the .xml entension.

Be sure to add the XML file to your project's Objects/res/drawable folder and make it read-only.

Martin.
 

warwound

Expert
Licensed User
Longtime User
I have just replaced the original uploaded 2.00 library.

The original upload still had it's version set to 1.90, the attachment now has the correct version code 2.00 set.

Martin.
 

AscySoft

Active Member
Licensed User
Longtime User
But is it possible to use gradient values in setTabTextColorStateList XML file?

Another (stupid) suggestion: why make external read-only XML file for setTabTextColorStateList? Why didn't you made it available from code inside library itself?
 

warwound

Expert
Licensed User
Longtime User
But is it possible to use gradient values in setTabTextColorStateList XML file?

I've done some searching but found no way so far to use a Gradient as text color.
That's not to say it's impossible - i'll have to leave you to spend the time searching if you really want this feature.
If you find any examples post again.

Another (stupid) suggestion: why make external read-only XML file for setTabTextColorStateList? Why didn't you made it available from code inside library itself?

Read back on the last few posts - implementing a ColorListState in code would have taken more time than i can spare.
I'd have had to create a wrapper library with all the possible getter and setter methods to enable a ColorListState to be created in code.

The XML solution took me relatively little time and is very flexible.
If you find any XML examples that show how to use a Gradient as a text color you can probably use those examples without requiring me to update the library.

Martin.
 
Top