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,限制还是比较多的。
Android 动态Tab分页效果实现的更多相关文章
- Android 动态Tab分页效果
当前项目使用的是TabHost+Activity进行分页,目前要做个报表功能,需要在一个Tab页内进行Activity的切换.比方说我有4 个Tab页分别为Tab1,Tab2,Tab3,Tab4,现在 ...
- vue2.0使用动态组件实现tab切换效果(vue-cli)
<template> <div> <div>#动态组件实现tab切换效果#</div><br><br><br> &l ...
- Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24740977 Android如今实现Tab类型的界面方式越来越多,今天就把常见的 ...
- JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有)
前言:最近园子里多了许多谈语言.谈环境.谈逼格(格局)的文章,看看笑笑过后,殊不知其实都是然并卵.提升自己的技术才是王道.之前博主分享过多篇bootstrap组件的文章,引起了很多园友的关注和支持,看 ...
- ViewPager+GridView实现首页导航栏布局分页效果
如图是效果图用ViewPager+GridView实现首页导航栏布局分页效果来实现的效果 Demo下载地址:http://download.csdn.net/detail/qq_29774291/96 ...
- Android之Tab类总结
本文主要包括以下Tab类实现方式 FragmentTabHost+Fragment实现 传统的ViewPager实现 FragmentManager+Fragment实现 ViewPager+Frag ...
- 【转】提示框第三方库之MBProgressHUD iOS toast效果 动态提示框效果
原文网址:http://www.zhimengzhe.com/IOSkaifa/37910.html MBProgressHUD是一个开源项目,实现了很多种样式的提示框,使用上简单.方便,并且可以对显 ...
- JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化
前言:之前发表过一篇 JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有) ,收到很多园友的反馈,当然也包括很多诟病,因为上篇只是将功能实现了,很多细节都没有处理 ...
- ajax实现无刷新分页效果
基于jquery.pagination.js实现的无刷新加载分页数据效果. 简介与说明 * 该插件为Ajax分页插件,一次性加载数据,故分页切换时无刷新与延迟.如果数据量较大,加载会比较慢. * 分页 ...
随机推荐
- Linux安装VritualBox实现虚拟机win2003端口映射 支持远程
1. 使用VNC登录到Linux系统 2. 安装VritualBox 找到VritualBox的软件包 这里的是run格式的 可以直接在终端运行 需要几分钟时间 3.VritualBox新建虚拟机 ...
- Application Designer Security
This wiki page covers how to manage and restrict Application Designer security through permission li ...
- Asp.net MVC4 Knockoutjs BootStrap Ace NinJect Jqgrid sqlserver2008
Asp.net MVC4 Knockoutjs BootStrap Ace NinJect Jqgrid sqlserver2008
- [转发]导出Excel 格式 mso-number-format
应用中经常会遇到要从系统或数据库中导出数据平面文件,一般是导出到txt,csv或excel.txt和csv一般用在系统间的数据交换,而 excel一般有较好的显示效果,可以按照一定的模板导出,导出就不 ...
- 在Activity中设置new出来的TextView属性
//创建一个TextView---->textView TextView textView = new TextView(this); // 第一个参数为宽的设置,第二个参数为高的设置 te ...
- 在 Windows 7 環境安裝 Python 2.6.6
目前 Python 的最穩定的版本是 2.7.3 及 3.2.3,因為 2.x 與 3.x 語法並不是完全相容,在各版本之間也有些差異,所以建議還是各自安裝需要的版本… 艾小克工作環境是使用 2.6 ...
- python中的remove趣谈
首先我们要知道remove做的操作是顺序遍历list表,找到第一个匹配的项时删掉该项,并不会再往下找,那我们看下面的代码 mylist = [1,2,3] for i in mylist: print ...
- p ython笔记第一天
一.Linux基础 - 计算机以及日后我们开发的程序防止的服务器的简单操作 二.Python开发 http://www.cnblogs.com/wupeiqi/articles/5433893.htm ...
- Python科学计算利器——Anaconda
(搬运自我在SegmentFault的博客) 最近在用Python做中文自然语言处理.使用的IDE是PyCharm.PyCharm确实是Python开发之首选,但用于科学计算方面,还略有欠缺.为此我尝 ...
- WPF:将HTML RGB颜色值转化为Color对象的两种方式
(1)方式一: Color color1 = (Color)System.Windows.Media.ColorConverter.ConvertFromString("#E0E0E0&qu ...