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,210
  • TabHostExtras_v2_20.zip
    22 KB · Views: 3,054
Last edited:

Mahares

Expert
Licensed User
Longtime User
Martin, you are a genius. I like the TabhostExtra new ver. 2, particularly. setTabTextColorStateList. I use it in ICS and it works well.
1. Do you have to have an XML file in Objects/res/drawable folder for each project. Can projects share, mainly when the same file will do?
2. Is there a function in ver. 2 that allows the tabhost indicator text to be BOLD instead of NORMAL to enhance it when selected?
3. What is the alpha.zip file you posted. Is that a more up to date library or is i9t more a less to help an individual with his particular problem?
4. For your info, initially I forgot to make the file 'Read Only'. Not only I got an error, but the file was deleted. I did not realize how important for the file to be read only.
Thank you very much.
 

warwound

Expert
Licensed User
Longtime User
Martin, you are a genius.

:sign0156: lol!

1. Do you have to have an XML file in Objects/res/drawable folder for each project. Can projects share, mainly when the same file will do?

Yes each project requires it's own XML file, this question is a bit like another FAQ - that is 'does each project require it's own Code modules when it'd make sense for all projects to share a common single version of a Code module?'
With B4A at the moment you need a copy of the XML for each project.

2. Is there a function in ver. 2 that allows the tabhost indicator text to be BOLD instead of NORMAL to enhance it when selected?

Surpringly enough there seems to be no documented way to do this.
I've spent a while searching and it looked as though i could use the TextView setTextAppearance method with a selector defined in XML.
(Much like using the selector to define the ColorStateList).

But i've not found any examples yet where i can try to do this myself - i shall search some more and hopefully find a method.

3. What is the alpha.zip file you posted. Is that a more up to date library or is i9t more a less to help an individual with his particular problem?

I've deleted that zip file now, it was just an early version of the library so that the setting of text color could be tested.

Martin.
 

pcbtmr

Member
Licensed User
Longtime User
Hmmm

Not sure if this is possible but here goes. I have 3 layouts associated with 3 tabs. I want to send data from one layout to a second one and activate the second layout (and track accordingly with the associated tab). How do I do this? In essence, send data to layout 2 and activate layout 2 without tapping tab 2 but set tab 2 as the currently selected tab.

Many thanks.
 

warwound

Expert
Licensed User
Longtime User
I can't quite see what's going wrong with the code you posted - you'd do better to start afresh.
The example code you've adapted isn't really suited for this case, look at this code:

B4X:
'Activity module
Sub Process_Globals

End Sub

Sub Globals
   Dim BasicLabel As Label
   Dim TabPanel As Panel
   Dim ScrollView1 As ScrollView
   Dim TabHost1 As TabHost
End Sub

Sub Activity_Create(FirstTime As Boolean)
   ScrollView1.Initialize(200%y)
   TabHost1.Initialize("TabHost1")
   
   ScrollView1.Panel.AddView(TabHost1, 0, 0, 100%x, 200%y)
   
   Activity.AddView(ScrollView1, 0, 0, 100%x, 100%y)
   
   TabHost1.AddTab("Tab1", "TabPanel")
   TabPanel.Width=-1
   TabPanel.Height=-1
   '   here you could load another layout in TabPanel etc
   BasicLabel.Text="This is tab1, width and height set to -1 fill parent (in code)"
   
   TabHost1.AddTab("Tab2", "TabPanel")
   TabPanel.Width=ScrollView1.Panel.Width
   TabPanel.Height=200%y
   BasicLabel.Text="This is tab2, height 200%y"
   
   TabHost1.AddTab("Tab3", "TabPanel")
   BasicLabel.Text="This is tab3, no width or height set (in code)"
   
   TabHost1.AddTab("Tab4", "TabPanel")
   TabPanel.Width=ScrollView1.Panel.Width
   TabPanel.Height=ScrollView1.Panel.Height
   BasicLabel.Text="This is tab4, width and height set to ScrollView1.Panel width and height"
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

The project is attached, run it and look at each tab, look for the rounded corners of each Panel.
You'll see that the only way to get the TabPanel to automatically fill the ScrollView Panel is to use the shorthand -1 to set Width and Height properties.

The code you posted tends to fail as it loads a layout file that is not a Panel containing Views but just the Views, with no parent Panel the layout fails to correctly size itself.

Now you have the main Panel of each tab correctly sized you can use TabHostExtras to customise it's appearance.

Martin.
 

Attachments

  • TabHostInScrollView.zip
    7.1 KB · Views: 341

cnicolapc

Active Member
Licensed User
Longtime User
setTabTextColorStateList Example

Hi,
Can you help me with a small example of "setTabTextColorStateList (tabHost1 As TabHost, ColorStateListName As String)"? and the xml file?
Thanks in advance.
Nicola
 

warwound

Expert
Licensed User
Longtime User
Hi,
Can you help me with a small example of "setTabTextColorStateList (tabHost1 As TabHost, ColorStateListName As String)"? and the xml file?
Thanks in advance.
Nicola

Take a look at this simple example:

B4X:
Sub Process_Globals

End Sub

Sub Globals
   Dim TabHost1 As TabHost
End Sub

Sub Activity_Create(FirstTime As Boolean)
   TabHost1.Initialize("TabHost1")
   
   Dim Label1 As Label
   Label1.Initialize("")
   Label1.Text="This is the first tab"
   TabHost1.AddTab2("Tab#1", Label1)

   Dim Label2 As Label
   Label2.Initialize("")
   Label2.Text="This is the second tab"
   TabHost1.AddTab2("Tab#2", Label2)
   
   ' Dim TabHostExtras1 As TabHostExtras
   ' TabHostExtras1.setTabTextColorStateList(TabHost1, "tab_widget_text_colors")
   
   Activity.AddView(TabHost1, 0, 0,100%x, 100%y)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

In the project's Objects\res\drawable folder is an XML file named tab_widget_text_colors.xml, it's attributes are set to read-only.
This is the XML file contents:

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>

Run the demo with the two TabHostExtras lines commented out and you'll see the default style of the device that you're running the demo on.
(Different devices have different default styles).

Now uncomment the two TabHostExtras lines.
The text label for the currently selected tab will be blue and the text label(s) for unselected tab(s) will be red.

More info on the ColorStateList can be found: https://www.google.co.uk/search?q=android+colorstatelist+xml&ie=UTF-8&oe=UTF-8

Martin.
 

Attachments

  • TabWidgetTextColors.zip
    6.2 KB · Views: 272

jalle007

Active Member
Licensed User
Longtime User
i am getting strange error all the time
B4X:
TabHost1.AddTab("List", "lyList")
java.lang.RuntimeException: Object should first be initialized (TabHost).


   at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:45)
   at anywheresoftware.b4a.objects.ViewWrapper.getWidth(ViewWrapper.java:121)
   at anywheresoftware.b4a.objects.TabHostWrapper.createPanelForLayoutFile(TabHostWrapper.java:113)
   at anywheresoftware.b4a.objects.TabHostWrapper.AddTab(TabHostWrapper.java:103)
   at b4a.freewifi.main._activity_create(main.java:293)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:167)
   at b4a.freewifi.main.afterFirstLayout(main.java:89)
   at b4a.freewifi.main.access$100(main.java:16)
   at b4a.freewifi.main$WaitForLayout.run(main.java:74)
   at android.os.Handler.handleCallback(Handler.java:725)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:5191)
   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:799)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566)
   at dalvik.system.NativeStart.main(Native Method)
java.lang.RuntimeException: Object should first be initialized (TabHost).
** Activity (main) Resume **
from this code

B4X:
#Region  Project Attributes 
   #ApplicationLabel: b4FreeWifi
   #VersionCode: 1
   #VersionName: 
   'SupportedOrientations possible values: unspecified, landscape or portrait.
   #SupportedOrientations: unspecified
   #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes 
   #FullScreen: False
   #IncludeTitle: True
#End Region

Sub Process_Globals
   Dim CurrentTab As Int
   Dim TabCount As Int : TabCount=3
   Dim TabHeight As Int
   Dim TabsEnabled(TabCount) As Boolean
   Dim TabsVisibility(TabCount) As Boolean
End Sub

Sub Globals
   Dim Button1 As Button
   Dim Button2 As Button
   Dim EnableButtons(TabCount) As Button
   Dim EditText1 As EditText
   Dim Label1 As Label
   Dim ShowHideButtons(TabCount) As Button
   Dim TabHost1 As TabHost
   Dim TabManager As TabHostExtras
   Dim WebView1 As WebView
   Dim lvList As ListView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   Activity.LoadLayout("lyMain")
Dim i As Int
   If FirstTime Then
      TabHost1.Initialize("TabHost1")
      
      CurrentTab=1
      '   start with a default tab height of 42 pixels
      TabHeight=42
      For i=0 To TabCount-1
         TabsEnabled(i)=True
         TabsVisibility(i)=True
      Next
   End If
   
      Log(TabHost1.IsInitialized)   
      TabHost1.AddTab("List", "lyList")
      TabHost1.AddTab("Add", "lyAdd")
      TabHost1.AddTab("Map", "lyMap")

   'setTabs

End Sub

But I am sure TabHost1 is initialized. Why is that , please?
 
Last edited:

jalle007

Active Member
Licensed User
Longtime User
tried that too but it did not help
B4X:
Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   Activity.LoadLayout("lyMain")

   If FirstTime Then
      Dim i As Int
      TabHost1.Initialize("TabHost1")
      
      CurrentTab=1
      '   start with a default tab height of 42 pixels
      TabHeight=42
      For i=0 To TabCount-1
         TabsEnabled(i)=True
         TabsVisibility(i)=True
      Next
   
      Log(TabHost1.IsInitialized)   
      TabHost1.CurrentTab=1
      
      'TabHost1.AddTab("List", "lyList")
      TabHost1.AddTab("Add", "lyAdd")
      TabHost1.AddTab("Map", "lyMap")
   End If

End Sub

and here is ss of my layout dir.

any ideas, please?
 

Attachments

  • UhzRKcm.png
    UhzRKcm.png
    4.1 KB · Views: 278

klaus

Expert
Licensed User
Longtime User
I suggested you this and not what you did:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("lyMain")

    Dim i As Int
    TabHost1.Initialize("TabHost1")
        
    CurrentTab=1
    '    start with a default tab height of 42 pixels
    TabHeight=42
    For i=0 To TabCount-1
        TabsEnabled(i)=True
        TabsVisibility(i)=True
    Next
    
    Log(TabHost1.IsInitialized)    
    TabHost1.CurrentTab=1
        
    'TabHost1.AddTab("List", "lyList")
    TabHost1.AddTab("Add", "lyAdd")
    TabHost1.AddTab("Map", "lyMap")
End Sub
Best regards.
 

jalle007

Active Member
Licensed User
Longtime User
here is the project attached.

it is strange because sometimes it work and then it stops.
I think it has something to do with package name and/or manifest file.

error , very frustrating:
B4X:
java.lang.RuntimeException: Object should first be initialized (TabHost).

please check
 

Attachments

  • FreeWifi.zip
    28.4 KB · Views: 246
Last edited:

klaus

Expert
Licensed User
Longtime User
I tried your program.
I needed to add
B4X:
Activity.AddView(TabHost1, 0, 0, 100%x, 100%y)
Then it works OK for me on both devices:
- Nexus One
- Asus TF700

How does the problem appear on your device ?

Best regards.
 

Attachments

  • FreeWifi_1.zip
    21.4 KB · Views: 247

Slacker

Active Member
Licensed User
Longtime User
Hello folks...Should it be possible with this library to mix text and images in the tab title location ? I'm trying to figure out how to add image and text in separate line (image on top and text in bottom in the tab title location) but without success....could you give me some tips ?

Thank you !
 

warwound

Expert
Licensed User
Longtime User
A lot depends on which version of android you are targetting, since ICS the TabHost will display icons only if no text has been set: http://www.b4x.com/forum/basic4andr...9420-tabhost-i-cant-see-icons.html#post170746.

I'm not sure if TabHostExtras can change this behavior or not.

There's seems to be solution where you can set your own tab indicator (the view that displays the text/icon) and then have full control over what is displayed: android - Icon in Tab is not showing up - Stack Overflow.

That'd require an update to TabHostExtras - can't promise to do that right away as i am busy with various other projects.
But if you want me to look at such an update then please post again and i'll put it on my list of 'things to do'.

Martin.
 

Slacker

Active Member
Licensed User
Longtime User
Thank you Martin. I think this feature is so much desidered from all users because it opens a lot of useful scenarios by using TabHost View.

If i can suggest some tips, it could be useful even if should be possible to overlap several images in "position absolute" style inside the tab indicator, with text included (imaging if one wants to overlap text where appear notifies facebook-style with the little numbers near the icon....).

I have to workaround now simulating this feature and TabHost view, using ImageView and Panel views...but it's harder 'cause i have to write down a lot of code to figure out it.

Insert it in "todo" list thank you but when you will implement it i think i'll have finished my APP :)

I will use it for next App in future then...:)
 
Top