Android 动态Tab分页效果

当前项目使用的是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,限制还是比较多的。

时间: 2024-07-29 09:47:36

Android 动态Tab分页效果的相关文章

(转载)Android两种Tab分页的方式:TabActivity和ActivityGroup以及Android项目几种常见的应用架构

在Android里面Tab分页,常用的方法有两种: 一.TabActivity和TabHost的结合 1.主类继承TabActivity public class Tagpage extends TabActivity 2.获取当前TabHost对象 final TabHost tabHost = getTabHost(); 3.添加Tab分页标签,这里就是关键,把每个分页面链接成Activity.页面的跳转,即是Activity的跳转. tabHost.addTab(tabHost.newTa

dedeCMS实现tab分页

说明: 1.tab分页效果预览网址1:http://bgjs.152app.com/plus/list.php?tid=5 网址2:http://yz.152app.com/plus/list.php?tid=1 2.原理:和自带的dedeajax2.js分页原理差不多,但看起来更简单.通过Ajax实现,使用jquery封装好的Ajax函数,获取从数据库里面输出的分页信息: 3.主要文件: 引入jquery文件: list_news.html(PS:新闻列表页): news_style.css(

Android入门之ActivityGroup + GridView 实现Tab分页标签

很多客户端软件和浏览器软件都喜欢用 Tab 分页标签来搭建界面框架.读者也许会马上想到使用 TabHost 与 TabActivity 的组合,其实最常用的不是它们,而是由 GridView 与 ActivityGroup 的组合.每当用户在 GridView 选中一项, ActivityGroup 就把该项对应的 Activity 的 Window 作为 View 添加到 ActivityGroup 所指定的容器 (LinearLayout) 中. 接下来贴出本例运行的效果图 : ImageA

【FastDev4Android框架开发】Android Design支持库TabLayout打造仿网易新闻Tab标签效果(三十七)

转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/50158985 本文出自:[江清清的博客] (一).前言: 仿36Kr客户端开发过程中,因为他们网站上面的新闻文章分类比较多,所以我这边还是打算模仿网易新闻APP的主界面新闻标签Tab以及页面滑动效果来进行实现.要实现的顶部的Tab标签的效果有很多方法例如采用开源项目ViewPagerIndicator中的TabPageIndicator就可以实现.不过我们今天不讲V

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

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24740977 Android现在实现Tab类型的界面方式越来越多,今天就把常见的实现方式给大家来个总结.目前写了: 1.传统的ViewPager实现 2.FragmentManager+Fragment实现 3.ViewPager+FragmentPagerAdapter实现 4.TabPageIndicator+ViewPager+FragmentPagerAdapter 1

spring mvc +HTML5实现移动端底部上滑异步加载更多内容分页效果

由于手机的携带的方便性和手机的越来越智能和移动网速越来越快,手机已经充斥着人们的生活.随着手机的流行, 移动应用也快速的火了起来比如微商城.手机网页.移动APP等等.既然移动应用这么火,我们今天来讲一下怎样实现在移 动网页中动态加载数据,那么我们怎么实现呢,是像pc网页那样,有个上一页和下一页还是其它的方式. 其实像pc网页那样上一页和下一页肯定不行的,手机屏幕很小,不好点击同时用户体验很差,今天来给大家介绍使用 spring mvc +HTML5实现移动端底部上滑异步加载更多内容分页效果的方式

(转载)Android项目tab类型主界面总结

Android实现tab类型的界面方式主要有以下几种: 1.传统的ViewPager实现(ViewPager+ViewAdapter) 2.FragmentManager+Fragment实现 3.ViewPager+FragmentPagerAdapter实现 4.TabPageIndicator+ViewPager+FragmentPagerAdapter 1.传统的ViewPager实现 ViewPager+ViewAdapter package com.example.mainframe

使用viewpageadapter实现tab分页

转载请注明出处:http://blog.csdn.net/xiaanming/article/details/10766053 之前用JakeWharton的开源框架ActionBarSherlock和ViewPager实现了对网易新闻客户端Tab标签的功能,ActionBarSherlock是在3.0以下的机器支持ActionBar的功能,有兴趣的可以看看开源框架ActionBarSherlock 和 ViewPager 仿网易新闻客户端,今天用到的是JakeWharton的另一开源控件Vie

第八十五讲:GridView和ActivityGroup实现的Tab分页

逆境是成长必经的过程,能勇于接受逆境的人,生命就会日渐的茁壮. 本讲内容:GridView和ActivityGroup实现的Tab分页 一.ActivityGroup相关--getLocalActivityManager() 以及intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)用法 1.ActivityGroup中可以调用getLocalActivityManager()方法获取LocalActityManager来管理Activity. 2.Loc