当前项目使用的是TabHost+Activity进行分页,目前要做个报表功能,需要在一个Tab页内进行Activity的切换。比方说我有4个Tab页分别为Tab1,Tab2,Tab3,Tab4,现在的需求是需要将Tab1内的Activity动态切换。找了很多资料最终使用了ActivityGroup解决了问题,在这过程中顺便尝试了一下使用Fragment+FragmentActivity+TabHost和Fragment+FragmentActivity+ActionBar试图淘汰掉旧版的ActivityGroup和TabHost,但是发现如果要使用Fragment,我需要修改已有的各个Tab页内的Activity,工作量较大,而使用ActionBar还有着许多版本兼容性问题,并且ActionBar不支持多层嵌套,最终放弃。现在写一下我个人实验用的TabHost+ActivityGroup、Fragment+FragmentActivity+TabHost和Fragment+FragmentActivity+ActionBar的Demo,供参考。

首先是TabHost+ActivityGroup。在最初的想法中,我是使用通过清空TabHost现有内容,再添加新内容来实现动态加载Tab页效果,具体代码不说了,举个例子:我有4个Tab页分别为Tab1、Tab2、Tab3和Tab4,存放4个Activity分别为Tab1Activity、Tab2Activity、Tab3Activity和Tab4Activity,现在我需要将Tab1位置的Tab1Activity变成Tab5Activity,我的做法是先全部清空,然后重新添加Tab1、Tab2、Tab3和Tab4,在添加的时候,将Tab1指向的Activity变成Tab5Activity。这种方法无疑是非常蠢得,而且在这一切换之后,会发现Ta5Activity的生命周期出现异常,每次在Tab1和其他Tab之间切换时,Ta5Activity都会被destroy掉重新create。这个问题我至今没找到原因。

然后找到了ActivityGroup。ActivityGroup也是继承至Activity类,可以看成是一个Actvity的容器类。 以上面的例子为例,当我们把ActivityGroup放入Tab1内时,我们就可以通过管理ActivityGroup来达到动态切换Activity的效果,贴上ActivityGroup的代码:

public class ActivityGroup1 extends ActivityGroup {
private ScrollView container = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
//存放Activity的容器
container = (ScrollView) findViewById(R.id.containerBody);
// 模块1
ImageView btnModule1 = (ImageView) findViewById(R.id.btnModule1);
btnModule1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//清空容器内现有内容
container.removeAllViews();
//加载activity
container.addView(getLocalActivityManager().startActivity(
"Module1",
new Intent(ActivityGroup1.this, Tab1Activity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
.getDecorView());
}
}); // 模块2
ImageView btnModule2 = (ImageView) findViewById(R.id.btnModule2);
btnModule2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
container.removeAllViews();
container.addView(getLocalActivityManager().startActivity(
"Module2",
new Intent(ActivityGroup1.this, Tab2Activity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
.getDecorView());
}
}); // 模块3
ImageView btnModule3 = (ImageView) findViewById(R.id.btnModule3);
btnModule3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
container.removeAllViews();
container.addView(getLocalActivityManager().startActivity(
"Module3",
new Intent(ActivityGroup1.this, Tab3Activity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
.getDecorView());
}
});
}
}

layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:orientation="vertical"
android:layout_height="fill_parent">
<LinearLayout android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/cust_title" android:textColor="@android:color/white"
android:textSize="28sp" android:text="模块1" android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
<!-- 中间动态加载View -->
<ScrollView android:measureAllChildren="true" android:id="@+id/containerBody"
android:layout_weight="1" android:layout_height="fill_parent"
android:layout_width="fill_parent">
</ScrollView>
<LinearLayout android:background="@android:color/black"
android:layout_gravity="bottom" android:orientation="horizontal"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<!-- 功能模块按钮1 -->
<ImageView android:id="@+id/btnModule1" android:src="@android:drawable/ic_dialog_dialer"
android:layout_marginLeft="7dp" android:layout_marginTop="3dp"
android:layout_marginBottom="3dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!-- 功能模块按钮2 -->
<ImageView android:id="@+id/btnModule2" android:src="@android:drawable/ic_dialog_info"
android:layout_marginLeft="7dp" android:layout_marginTop="3dp"
android:layout_marginBottom="3dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!-- 功能模块按钮3 -->
<ImageView android:id="@+id/btnModule3" android:src="@android:drawable/ic_dialog_alert"
android:layout_marginLeft="7dp" android:layout_marginTop="3dp"
android:layout_marginBottom="3dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

在TabHost中的调用方式和普通的activity一样

TabSpec tabSpec=mtabHost.newTabSpec("1").setIndicator("TAB1").setContent(
new Intent(this, FragmentActivity1.class));
mtabHost.addTab(tabSpec);

这样通过点击三个按钮就能达到动态切换Activity的效果了。

顺便说下,当ActivityGroup内嵌套Activity时,Activity的生命周期跟TabHost内嵌套Activity一样。具体的百度。

较新的版本中TabHost和ActivityGroup都已经被淘汰了,取而代之的是FragmentActivity+Fragment。但我很疑惑Fragment是否真能完全取代ActivityGroup的效果。就拿上述功能来说,我要想使用FragmentActivity替换ActivityGroup,那么我现有的Activity就必须重写,改装成Fragment。这种情况下,我在其他地方要使用这些Activity该怎么办呢?我没找到如何使用Fragment装载Activity的办法,所以暂时就没法用FragmentActivity替代ActivityGroup了。贴下使用FragmentActivity+Fragment+TabHost的实现代码:

Fragment1Activity:

public class FragmentActivity1 extends FragmentActivity{
public static FragmentManager fm;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_acitivity_1);
fm = getSupportFragmentManager();
// 只當容器,主要內容已Fragment呈現
initFragment(new Fragment1());
}
/**
*
*/ // 切換Fragment
public static void changeFragment(Fragment f){
changeFragment(f, false);
}
// 初始化Fragment(FragmentActivity中呼叫)
public static void initFragment(Fragment f){
changeFragment(f, true);
}
private static void changeFragment(Fragment f, boolean init){
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.simple_fragment, f);
if(!init)
ft.addToBackStack(null);
ft.commit();
}
}

这里的FragmentActivity1并不显示具体内容,只做Fragment得容器使用,具体显示内容通过调用changeFragment方法动态加载。

Fragment1和Fragment2的代码如下,点击按钮两者互相切换:

public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment1, container, false);
Button tv = (Button)v.findViewById(R.id.button2);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 直接呼叫FragmentActivity1的靜態方法來做切換
FragmentActivity1.changeFragment(new Fragment2());
}
});
return v;
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment2, container, false);
Button tv = (Button)v.findViewById(R.id.button2);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 直接呼叫FragmentActivity1的靜態方法來做切換
FragmentActivity1.changeFragment(new Fragment1());
}
});
return v;
}
}

同样,在TabHost添加中跟普通的Activity一样:

TabSpec tabSpec=mtabHost.newTabSpec("1").setIndicator("TAB1").setContent(
new Intent(this, FragmentActivity1.class));
mtabHost.addTab(tabSpec);

这三者的layout都很简单,就不写了。对比ActivityGroup方法发现,其实两者实现思路是一样的,都是先用一个“容器”(ActivityGroup和FragmentActivity)占住Tab1的位置,然后每次相应时,通过改变“容器”内的元素来达到动态改变的效果,区别就是ActivityGroup存放的是Activity,而FragmentActivity存放的是Fragment。(本人目前已经知道可以将Fragment嵌套到Activity中,是否有方法可以将Activity嵌套到Fragment中呢?那么就可以达到两个方法的完全兼容了,而不用像我我担心的,需要改造目前已有的Activity成Fragment来达到使用FragmentActivity替换ActivityGroup的效果)

最后说下ActionBar+FragmentActivity+Fragment来替换掉TabHost。在使用过程中发现这个ActionBar限制有点多,于是舍弃了,贴下实现代码。

public class FragmentActivity1 extends FragmentActivity implements ActionBar.TabListener{
public static FragmentManager fm;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_acitivity_1);
fm = getSupportFragmentManager();
ActionBar actionBar=this.getActionBar();
this.getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
this.getActionBar().setDisplayShowTitleEnabled(false);
this.getActionBar().setDisplayShowHomeEnabled(false);
setBar("Tab 1");
setBar("Tab 2");
setBar("Tab 3");
setBar("Tab 4");
// 只當容器,主要內容已Fragment呈現
initFragment(new Fragment1());
}
/**
*
*/
private void setBar(String s) {
Tab tab = this.getActionBar().newTab();
tab.setContentDescription(s);
tab.setText(s);
tab.setTabListener(this);
getActionBar().addTab(tab);
}
// 切換Fragment
public static void changeFragment(Fragment f){
changeFragment(f, false);
}
// 初始化Fragment(FragmentActivity中呼叫)
public static void initFragment(Fragment f){
changeFragment(f, true);
}
private static void changeFragment(Fragment f, boolean init){
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.simple_fragment, f);
if(!init)
ft.addToBackStack(null);
ft.commit();
}
@Override
public void onTabReselected(Tab arg0, android.app.FragmentTransaction arg1) {
// TODO Auto-generated method stub }
@Override
public void onTabSelected(Tab arg0, android.app.FragmentTransaction arg1) {
// TODO Auto-generated method stub
if(arg0.getText().equals("Tab 1"))
{
changeFragment(new Fragment1());
}
else {
changeFragment(new Fragment2());
}
}
@Override
public void onTabUnselected(Tab arg0, android.app.FragmentTransaction arg1) {
// TODO Auto-generated method stub }
}

在minSdkVersion设置为11后就能调用getActionBar()方法了,可以给它添加tab,然后重点是为ActionBar.TabListener写点击Tab时要实现的功能,这里我进行了Fragment的切换,以达到TabHost相同的效果。要注意的是如果该FragmentActivity是嵌套在其他Activity中(比方说TabHost)时,getAction将会返回null,即无法进行分页,其他情况下也有可能返回null,限制还是比较多的。

Android 动态Tab分页效果实现的更多相关文章

  1. Android 动态Tab分页效果

    当前项目使用的是TabHost+Activity进行分页,目前要做个报表功能,需要在一个Tab页内进行Activity的切换.比方说我有4 个Tab页分别为Tab1,Tab2,Tab3,Tab4,现在 ...

  2. vue2.0使用动态组件实现tab切换效果(vue-cli)

    <template> <div> <div>#动态组件实现tab切换效果#</div><br><br><br> &l ...

  3. Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24740977 Android如今实现Tab类型的界面方式越来越多,今天就把常见的 ...

  4. JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有)

    前言:最近园子里多了许多谈语言.谈环境.谈逼格(格局)的文章,看看笑笑过后,殊不知其实都是然并卵.提升自己的技术才是王道.之前博主分享过多篇bootstrap组件的文章,引起了很多园友的关注和支持,看 ...

  5. ViewPager+GridView实现首页导航栏布局分页效果

    如图是效果图用ViewPager+GridView实现首页导航栏布局分页效果来实现的效果 Demo下载地址:http://download.csdn.net/detail/qq_29774291/96 ...

  6. Android之Tab类总结

    本文主要包括以下Tab类实现方式 FragmentTabHost+Fragment实现 传统的ViewPager实现 FragmentManager+Fragment实现 ViewPager+Frag ...

  7. 【转】提示框第三方库之MBProgressHUD iOS toast效果 动态提示框效果

    原文网址:http://www.zhimengzhe.com/IOSkaifa/37910.html MBProgressHUD是一个开源项目,实现了很多种样式的提示框,使用上简单.方便,并且可以对显 ...

  8. JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化

    前言:之前发表过一篇  JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有) ,收到很多园友的反馈,当然也包括很多诟病,因为上篇只是将功能实现了,很多细节都没有处理 ...

  9. ajax实现无刷新分页效果

    基于jquery.pagination.js实现的无刷新加载分页数据效果. 简介与说明 * 该插件为Ajax分页插件,一次性加载数据,故分页切换时无刷新与延迟.如果数据量较大,加载会比较慢. * 分页 ...

随机推荐

  1. Linux安装VritualBox实现虚拟机win2003端口映射 支持远程

    1. 使用VNC登录到Linux系统 2. 安装VritualBox 找到VritualBox的软件包 这里的是run格式的 可以直接在终端运行  需要几分钟时间 3.VritualBox新建虚拟机 ...

  2. Application Designer Security

    This wiki page covers how to manage and restrict Application Designer security through permission li ...

  3. Asp.net MVC4 Knockoutjs BootStrap Ace NinJect Jqgrid sqlserver2008

    Asp.net MVC4 Knockoutjs  BootStrap Ace NinJect  Jqgrid sqlserver2008

  4. [转发]导出Excel 格式 mso-number-format

    应用中经常会遇到要从系统或数据库中导出数据平面文件,一般是导出到txt,csv或excel.txt和csv一般用在系统间的数据交换,而 excel一般有较好的显示效果,可以按照一定的模板导出,导出就不 ...

  5. 在Activity中设置new出来的TextView属性

    //创建一个TextView---->textView TextView textView = new TextView(this);   // 第一个参数为宽的设置,第二个参数为高的设置 te ...

  6. 在 Windows 7 環境安裝 Python 2.6.6

    目前 Python 的最穩定的版本是 2.7.3 及 3.2.3,因為 2.x 與 3.x 語法並不是完全相容,在各版本之間也有些差異,所以建議還是各自安裝需要的版本… 艾小克工作環境是使用 2.6 ...

  7. python中的remove趣谈

    首先我们要知道remove做的操作是顺序遍历list表,找到第一个匹配的项时删掉该项,并不会再往下找,那我们看下面的代码 mylist = [1,2,3] for i in mylist: print ...

  8. p ython笔记第一天

    一.Linux基础 - 计算机以及日后我们开发的程序防止的服务器的简单操作 二.Python开发 http://www.cnblogs.com/wupeiqi/articles/5433893.htm ...

  9. Python科学计算利器——Anaconda

    (搬运自我在SegmentFault的博客) 最近在用Python做中文自然语言处理.使用的IDE是PyCharm.PyCharm确实是Python开发之首选,但用于科学计算方面,还略有欠缺.为此我尝 ...

  10. WPF:将HTML RGB颜色值转化为Color对象的两种方式

    (1)方式一: Color color1 = (Color)System.Windows.Media.ColorConverter.ConvertFromString("#E0E0E0&qu ...