想要制作出拥有多个Tab相互切换的界面,需要用到几个主要的组件:

1. android.app.TabActivity;

2. android.widget.TabHost;

3. android.view.LayoutInflater;

4. android.widget.TabWidget

5. android.widget.FrameLayout


本文描述了制作Tabs界面的三种常用方法,参考来自于Android官方文档及ApiDemo。

在此需要特别说明:android.app.TabActivity;在api13已经被视为废弃组件,官方推荐使用android.app.Fragment,但是如果为了兼容低版本设备,则可以使用v4 support library提供的fragment api。

即便如此,预先学习一下旧式的TabActivity,也能更好地学习Fragment。


效果图和示例代码:

1.主界面

Android之TabHost_第1张图片

activity_main.xml


    

MainActivity.java

package com.panny.tabsdemo;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class MainActivity extends Activity {
                                                                                                                   
    private ListView lstvDemos;
                                                                                                                   
    private String[] contents = new String[]{
            "Content By Id",
            "Content By Factory",
            "Content By Intent",
            "Scrollable"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);
                                                                                                                       
        this.lstvDemos = (ListView) findViewById(R.id.lstv_demos);
        ArrayAdapter adapter = new ArrayAdapter(
                getCurrentContext(),
                android.R.layout.simple_list_item_1,
                contents);
        this.lstvDemos.setAdapter(adapter);
                                                                                                                       
        this.lstvDemos.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view,
                    int position, long id) {
                                                                                                                               
                switch (position) {
                case 0:
                    startActivity(new Intent(getCurrentContext(), ContentByIdActivity.class));
                    break;
                case 1:
                    startActivity(new Intent(getCurrentContext(), TabByContentFactoryActivity.class));
                    break;
                case 2:
                    startActivity(new Intent(getCurrentContext(), TabByIntentActivity.class));
                    break;
                case 3:
                    startActivity(new Intent(getCurrentContext(), ScrollableActivity.class));
                    break;
                default:
                    break;
                }
                                                                                                                               
            }
        });
    }
                                                                                                                   
    private MainActivity getCurrentContext() {
        return MainActivity.this;
    }
}

2.Content By Id

Android之TabHost_第2张图片

ContentByIdActivity.java

package com.panny.tabsdemo;
import android.os.Bundle;
import android.app.TabActivity;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.TabHost;
public class ContentByIdActivity extends TabActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                                                                                                             
        /*
         * TabHost作为标签窗体试图的容器。
         * 这个对象包含两个元素,第一个是一个包含了若干个标签名称的集合,用户通过点击它来切换标签视图;
         * 第二个是一个帧布局对象,用于显示被选中标签的内容。
         * 实际上它们是相互映射,并且相互独立的,但是它们的内容均由TabHost容器控制,而非它们自身。
         */
        TabHost tabHost = getTabHost(); // 如果用户没有自定义id为@android:id/tabhost的,那么将自动从系统获取。
                                                                                                             
        /*
         * 首先通过系统服务获取已经在当前上下文挂载并且与设备配置好的LayoutInflater实例
         * 这一点必须讲究一下,因为某些文档会直接使用:LayoutInflater.from(this).inflate(...)
         * 虽然这并不影响运行效果,但是可能会有部分性能消耗,即使不是很大,但我们也应该注意。
         */
        LayoutInflater inflter = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        /*
         * LayoutInflater的作用是将layout布局文件转换成为View实例,正如第一个参数所为;
         * 第二个参数的作用是把tabHost.getTabContentView()得到的FrameLayout实例作为root;
         * 第三个参数的作用是将第一个参数的View挂载在root下。
         */
        inflter.from(getCurrentContext()).inflate(R.layout.activity_content_by_id, tabHost.getTabContentView(), true);
                                                                                                             
        /*
         * TabHost实例负责控制tab增减
         * (1)创建一个标签空间,名称为tab01,但它不用于显示, 但它有自己的用处,可参看TabByContentFactoryActivity
         * (2)设置标签显示的名称,或许也可以添加一个背景图
         * (需要注意的是:在添加背景图使,笔者在emulator-api10 和 emulator-api17上的运行效果不同,emulator-api10可以允许同时添加label和drawable,
         * 而emulator-api17需要如此.setIndicator("", getResources().getDrawable(R.drawable.ic_launcher)))
         * (3)设置标签对应的内容
         */
        tabHost.addTab(
                tabHost.newTabSpec("tab01") // (1)
                .setIndicator("one", getResources().getDrawable(R.drawable.ic_launcher))// (2)
                .setContent(R.id.tv_view01)); // (3)
        tabHost.addTab(tabHost.newTabSpec("tab02").setIndicator("two").setContent(R.id.tv_view02));
        tabHost.addTab(tabHost.newTabSpec("tab03").setIndicator("three").setContent(R.id.tv_view03));
                                                                                                             
    }
                                                                                                         
    private ContentByIdActivity getCurrentContext() {
        return ContentByIdActivity.this;
    }
}

activity_content_by_id.xml


                                                                                           
    
                                                                                           
    
                                                                                           
    
                                                                                           


3.Content By Factory

Android之TabHost_第3张图片

TabByContentFactoryActivity.java

package com.panny.tabsdemo;
import android.app.TabActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TabHost;
import android.widget.TabHost.TabContentFactory;
import android.widget.TextView;
public class TabByContentFactoryActivity extends TabActivity implements TabContentFactory {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                                                                                      
        TabHost tabHost = getTabHost();
        tabHost.addTab(
                tabHost.newTabSpec("tab01")
                .setIndicator("one")
                .setContent(this));
                                                                                      
        tabHost.addTab(
                tabHost.newTabSpec("tab02")
                .setIndicator("two")
                .setContent(this));
                                                                                      
        tabHost.addTab(
                tabHost.newTabSpec("tab03")
                .setIndicator("three")
                .setContent(this));
    }
    @Override
    public View createTabContent(String tag) {
        TextView tv = new TextView(this);
        tv.setText("This is the " + tag); // 这个参数来自于:tabHost.newTabSpec("tab01")
        return tv;
    }
}


4.Content By Intent

Android之TabHost_第4张图片

TabByIntentActivity.java

package com.panny.tabsdemo;
import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TabHost;
public class TabByIntentActivity extends TabActivity {
                                                                        
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                                                                            
        TabHost tabHost = getTabHost();
                                                                            
        tabHost.addTab(
                tabHost.newTabSpec("list")
                .setIndicator("list")
                .setContent(new Intent(this, Cities.class)));
                                                                            
        tabHost.addTab(
                tabHost.newTabSpec("photos")
                .setIndicator("photos")
                .setContent(new Intent(this, Phones.class)));
                                                                            
    }
}

Cities.java

package com.panny.tabsdemo;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
public class Cities extends ListActivity {
                                                            
    private String[] cities = new String[]{
            "ShangHai", "BeiJin", "GuangZhou",
            "ChongQing", "WuHan", "FuJian",
            "XiAn", "HeiLongJiang", "QingDao"
    };
                                                            
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                                                                
        ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, cities);
        getListView().setAdapter(adapter);
    }
}

Android之TabHost_第5张图片

Phones.java

package com.panny.tabsdemo;
import java.util.ArrayList;
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
public class Phones extends ListActivity {
                                                   
    private Button btnAdd;
    private Button btnClear;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.photos_list);
                                                       
        this.btnAdd = (Button) findViewById(R.id.btn_add_photo);
        this.btnClear = (Button) findViewById(R.id.btn_clear_photos);
                                                       
        // 设置当listview为空时,应该显示什么视图,在此显示预先定义的TextView
        getListView().setEmptyView(findViewById(R.id.tv_empty));
                                                       
        final PhotoAdapter adapter = new PhotoAdapter(this);
        setListAdapter(adapter);
                                                       
        this.btnAdd.setOnClickListener(new View.OnClickListener() {
                                                           
            @Override
            public void onClick(View v) {
                adapter.add();
                                                               
            }
        });
        this.btnClear.setOnClickListener(new View.OnClickListener() {
                                                           
            @Override
            public void onClick(View v) {
                adapter.clear();
                                                               
            }
        });
                                                       
    }
                                                   
    private class PhotoAdapter extends BaseAdapter {
                                                       
        private Context mContext;
        private int[] photosPool = new int[]{
                R.drawable.sample_1, R.drawable.sample_2, R.drawable.sample_3,
                R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6,
                R.drawable.sample_7
        };
        // 为了动态添加图片,它才是adapter真正的内容提供者
        private ArrayList photos = new ArrayList();
                                                       
        public PhotoAdapter(Context mContext) {
            this.mContext = mContext;
        }
        @Override
        public int getCount() {
            return photos.size();
        }
        @Override
        public Object getItem(int position) {
            return photos.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView i = new ImageView(mContext);
                                                           
            i.setImageResource(photos.get(position));
            i.setAdjustViewBounds(true);
            i.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            i.setBackgroundResource(R.drawable.picture_frame);
            return i;
        }
                                                       
        private void add() {
            int wicthPic = (int) Math.round(Math.random() * (photosPool.length - 1));
            photos.add(photosPool[wicthPic]);
            notifyDataSetChanged();
        }
                                                       
        private void clear() {
            photos.clear();
            notifyDataSetChanged();
        }
    }
                                                   
                                                   
}

R.layout.photos_list.xml


                                             
    
                                                 
        


4.Scrollable

Android之TabHost_第6张图片

ScrollableActivity.java

package com.panny.tabsdemo;
import android.app.TabActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TabHost;
import android.widget.TabHost.TabContentFactory;
import android.widget.TextView;
public class ScrollableActivity extends TabActivity implements TabContentFactory {
                                     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tab_scroll); // 不要忘记加载自定义的布局文件
                                         
        TabHost tabHost = getTabHost();
                                         
        for(int i = 0; i < 30; i ++) {
            tabHost.addTab(
                    tabHost.newTabSpec("tab" + i)
                    .setIndicator("tab_" + i)
                    .setContent(this));
        }
    }
    @Override
    public View createTabContent(String tag) {
        TextView tv = new TextView(this);
        tv.setText("This is " + tag);
        return tv;
    }
}

R.layout.tab_scroll.xml



                               
    
                                   
        
                                       
            
            
                                       
        
        
        
                                   
    
                               


Best Regards,