android基础知识27:TabHost02——嵌套TabHost

今天讲一下,如何在TabHost中,再放TabHost。
先来看一下效果。

一层TabHost

      

两层Tabhost (内部TabHots在上面),如上右图所示。

两层TabHost (内层TabHots在下面)


下面说一下代码,一共3个 java类,3个xml布局文件。
看一下主画面:
main.xml

<?xml version="1.0" encoding="utf-8"?>  
<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"  
    android:background="@drawable/default_bg">  
    <LinearLayout android:orientation="vertical"   
        android:layout_width="fill_parent" android:layout_height="fill_parent">  
        <TabWidget android:id="@android:id/tabs"  
            android:layout_alignParentBottom="true" android:layout_width="fill_parent"  
            android:layout_height="wrap_content"/>  
        <FrameLayout android:id="@android:id/tabcontent"  
            android:layout_weight="1" android:layout_width="fill_parent"  
            android:layout_height="fill_parent" />  
    </LinearLayout>  
</TabHost>
就是常规的Tabhost布局。
入口类:
DoubleTabHost.java

package com.yfz;
import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TabHost;
/**
 * 本类继承了TabActivity
 * @author Administrator
 *
 */
public class DoubleTabHost extends TabActivity {
	
	 /* 注意:
	 * 对于TabHost、布局文件中必须包含
	 * TabHost、TabWidget 、FrameLayout 
	 * 如果继承TabActivity,并且通过getTabHost()方法来获取TabHost
	 * 那么三者的ID必须是android.R.id.tabhost、android.R.id.tabs、android.R.id.tabcontent
	 * 
	 * 如果继承Activity,可以通过findViewById来获取这三个组件,此时ID可自定义
	 */
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
		TabHost mTabHost = getTabHost();
		mTabHost.addTab(mTabHost.newTabSpec("Twitter").setIndicator(
				"Twitter",
				getResources().getDrawable(android.R.drawable.arrow_down_float)).setContent(
				new Intent(this, SubTab.class)));
		mTabHost.addTab(mTabHost.newTabSpec("Facebook").setIndicator(
				"Facebook",
				getResources().getDrawable(android.R.drawable.arrow_down_float)).setContent(
				new Intent(this, NormalActivity.class)));
		mTabHost.setCurrentTab(0);
    }
}


对于TabHost、布局文件中必须包含TabHost、TabWidget 、FrameLayout .缺一不可
如果加载该TabHost画面的类继承TabActivity,并且想通过getTabHost()方法来获取TabHost,getTabWidget()方法获取TabWidget,
那么TabHost、TabWidget 、FrameLayout 三者的ID必须是android.R.id.tabhost、android.R.id.tabs、android.R.id.tabcontent
否则会报运行时异常,错误如下:
TabHost ID错误:

ERROR/AndroidRuntime(8301): Caused by: java.lang.RuntimeException: Your content must have a TabHost whose id attribute is 'android.R.id.tabhost'  
TabWidget ID 错误:

ERROR/AndroidRuntime(8354): Caused by: java.lang.RuntimeException: Your TabHost must have a TabWidget whose id attribute is 'android.R.id.tabs' 
FrameLayout  ID错误:

ERROR/AndroidRuntime(8404): Caused by: java.lang.RuntimeException: Your TabHost must have a FrameLayout whose id attribute is 'android.R.id.tabcontent'  
子TabHost页面:
subtab.xml

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/mytabhost" android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:background="@drawable/default_bg">
	<LinearLayout android:orientation="vertical" 
		android:layout_width="fill_parent" android:layout_height="fill_parent">
		<!-- 注意FrameLayout/TabWidget标签的位置-->
		<FrameLayout android:id="@android:id/tabcontent"
			android:layout_weight="1" android:layout_width="fill_parent"
			android:layout_height="fill_parent" >
				<TextView
					android:id="@+id/widget59"
					android:layout_width="wrap_content"
					android:layout_height="wrap_content"
					android:text="你在想什么?"
					android:layout_alignParentTop="true"
					android:layout_centerHorizontal="true"
					>
					</TextView>
					<TextView
					android:id="@+id/widget60"
					android:layout_width="wrap_content"
					android:layout_height="wrap_content"
					android:text="我在想Android"
					android:layout_alignParentTop="true"
					android:layout_alignParentRight="true"
					>
					</TextView>
		</FrameLayout>
		<TabWidget android:id="@android:id/tabs"
			android:layout_alignParentBottom="true" android:layout_width="fill_parent"
			android:layout_height="wrap_content"/>
	</LinearLayout>
</TabHost>

子TabHost页面加载类:
SubTab.java

package com.yfz;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
/**
 * 
 * @author Administrator
 *
 */
public class SubTab extends Activity {
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.subtab);
        
        //以下三句代码,注意顺序
		TabHost mTabHost = (TabHost)findViewById(R.id.mytabhost);
		mTabHost.setup();
		TabWidget tabWidget = mTabHost.getTabWidget();
		
		mTabHost.addTab(mTabHost.newTabSpec("苏州").setIndicator(
				"苏州").setContent(R.id.widget59));
		mTabHost.addTab(mTabHost.newTabSpec("上海").setIndicator(
				"上海").setContent(R.id.widget60));
		mTabHost.addTab(mTabHost.newTabSpec("天津").setIndicator(
				"天津").setContent(R.id.widget60));
		mTabHost.addTab(mTabHost.newTabSpec("北京").setIndicator(
				"北京").setContent(R.id.widget60));
		mTabHost.setCurrentTab(0);
		
		int height =30; 
//		int width =45; 
	        
		for (int i =0; i < tabWidget.getChildCount(); i++) {
            
			/**设置高度、宽度,由于宽度设置为fill_parent,在此对它没效果 */ 
            tabWidget.getChildAt(i).getLayoutParams().height = height; 
//            tabWidget.getChildAt(i).getLayoutParams().width = width; 
            /**设置tab中标题文字的颜色,不然默认为黑色 */ 
             final TextView tv = (TextView) tabWidget.getChildAt(i).findViewById(android.R.id.title); 
             tv.setTextColor(this.getResources().getColorStateList(android.R.color.white)); 
		}
    }
}

如果加载TabHost画面的继承自Activity,可以通过findViewById来获取这三个组件,此时ID可自定义。
需要注意的是,此时必须调用setup方法来加载TabHost。
对了,不要忘了在AndroidManifest.xml定义Activity~~呵呵!
要点就这么多~ 就这样了。
源程序下载地址:    http://download.csdn.net/source/3037680
BUG对应。  感谢simayilong 和 gz116 提出这两个典型问题。
问题一:无法在子tabhost中打开Activity。

java.lang.IllegalStateException: Did you forget to call 'public void setup(LocalActivityManager activityGroup)'? 
解决办法1:
1. 将初始化tabHost的那个类(此例中为SubTab类),继承ActivityGroup,而不是Activity
2. tabhost.setup() 改为 tabHost.setup(this.getLocalActivityManager()); 
具体参考:
http://stackoverflow.com/questions/3272500/android-exception-did-you-forget-to-call-public-void-setup-localactivitymanage
http://hi.baidu.com/ljlkings/blog/item/47f1afdbdcd27de638012f76.html
解决办法2:
也可以将SubTab类改继承TabActivity,然后布局文件中Tabhost的id改为@android:id/tabhost.
因为TabActivity也是继承自ActivitGroup的。
以上两种方法都可以。
问题二:  TabHost 嵌套后,Dialog 不能显示

android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@43e57e20 is not valid; is your activity running?  
解决办法:
AlertDialog.Builder(xxx.this) => AlertDialog.Builder(xxx.this.getParent())

参考资料:

嵌套TabHost (TabHost中放TabHost,类似二级目录、二级树)

【Android进阶】嵌套TabHost (TabHost中放TabHost,类似二级目录、二级树)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值