标签(选项)式布局(Tab Layout)(基于 API 4 )---- (1)

来源:互联网 发布:手机网络理财 编辑:程序博客网 时间:2024/06/06 06:30

文章内容



1.  基于平台版本的标签应用


2.  把视图设置为标签内容


3.  实现TabHost.TabContentFactory接口


4.  把意图设置为标签内容





1. 基于平台版本的标签应用



       随着android API 标准的不断更新,创建标签式布局应用的方式也发生了变化。在android 1.6(API 4)版本以前(包括API 4),实现标签布局应用的代码需要扩展TabActivity。在android 1.6和android 3.0之间(不包括3.0),则需要引入静态库android.support.v4.app,扩展其中的FragmentActivity类。它也是那些想要使用支持基于FragmentLoader API的基类。在android 3.0以后,代码像创建普通活动一样,扩展Activity类,然后通过ActionBar创建和添加标签项。


       下面,简单地介绍一下平台版本基于API 4(及以前)时创建标签式布局应用需要掌握的知识点。


       标签布局主要由三部分组成构成,标签宿主,标签项和标签内容。标签宿主是持有标签项和标签内容的载体,也是创建标签项的发起者。在标签项上可以添加一个图标和标记用以追踪当前的焦点。不同的标签可以承载不同的内容。而标签内容则可以根据需要选择其实现的方式。具体来说,可以采用以下三种方式来实现标签内容:


       1. 为标签内容引用视图id(setTabContent by view Id);

       2. 通过实现标签宿主内的标签内容工厂类(implements TabHost.TabContentFactory);

       3. 为标签内容设置意图来加载活动(setTabContent by intent);


       无论采用哪种方式,都不得不说,实现标签内容才是标签式布局应用的本质所在。接下来,我们创建一个工程,并以此来逐一说明每种实现标签内容的方法。

    

       1.   创建一个新的android工程,命名为HelloTabWidget。

         2.   需要为每个标签准备状态小图标。一个是在标签被选中时显示,另一个则是在未被选中时显示。通常的设计建议是为选中的标签图标使用深色(灰色),而未被选中的标签图标则使用亮色(白色)。例如:


          (未被选中)        (被选中)


          作为演示,我们为三个标签使用同样的上述图标(实际开发中应该为不同的标签使用不同的自定义图标)。


        现在,创建一个state-list drawable 资源用来为每个标签的状态指定对应的图标。


  •          把图标保存到工程res/drawable/目录下;
  •         res/drawable/目录下创建一个XML文件,并命为ic_tab_artists.xml,且内容如下:

 

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <!-- 当标签被选中时使用灰色图标 -->    <item android:drawable="@drawable/ic_tab_artists_grey"          android:state_selected="true" />    <!-- 当标签未选中时使用白色图标-->    <item android:drawable="@drawable/ic_tab_artists_white" /></selector>

       

        关于state-list drawable 资源的创建可以参考:http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList


         准备工作已经做好了。接下来就逐一地使用不同的方法来为标签设置内容。


2. 把视图设置为标签内容


        首先,修改res/layout/下面的main.xml文件,修改后内容如下:


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <TextView android:id="@+id/tab_view1"        android:background="@drawable/blue"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:text="@string/tabs_1_tab_1"/>    <TextView android:id="@+id/tab_view2"        android:background="@drawable/red"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:text="@string/tabs_1_tab_2"/>    <TextView android:id="@+id/tab_view3"        android:background="@drawable/green"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:text="@string/tabs_1_tab_3"/></FrameLayout>

       

         在上述的布局文件里,包括了三个文本视图,目的是用他们来作为三个标签项的内容。注意,这三个视图的位置并没有指定,因此在切换标签时,他们的内容将会相互覆盖。


        然后,实现HelloWidget类,内容如下:


public class HelloTabWidget extends TabActivity {@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        @SuppressWarnings("deprecation")TabHost tabHost = getTabHost();        Resources res = getResources();                LayoutInflater.from(this).inflate(R.layout.main, tabHost.getTabContentView(), true);                 tabHost.addTab(tabHost.newTabSpec("tab1")                .setIndicator("tab1",res.getDrawable(R.drawable.ic_tab_artists))                .setContent(R.id.view1));        tabHost.addTab(tabHost.newTabSpec("tab3")                .setIndicator("tab2" ,res.getDrawable(R.drawable.ic_tab_artists))                .setContent(R.id.view2));        tabHost.addTab(tabHost.newTabSpec("tab3")                .setIndicator("tab3",res.getDrawable(R.drawable.ic_tab_artists))                .setContent(R.id.view3));       tabHost.setCurrentTab(1);       }}

       在HelloWidget类内,创建了三个标签,并为每个标签内容引用了三个不同的视图id,当切换标签时,他们引用的视图将出现在标签项的下方。这一点可以从main.xml布局文件里看的出来。同时,我们还为三个标签设置了相同的小图标,用来凸显标签当前是否被选中。


         作为演示,该类内只重写了onCreate方法。该方法内的主要工作包括如下方面:


        1. 获取用来持有标签项的宿主(TabHost),因为接下来的操作都是通过宿主来完成的;

        2. 创建标签项(TabHost.TabSpec );

        3. 为每个标签项设置属性,主要包括:

            3.1 设置标记;

            3.2 指定用于在标签上显示的图标和文本;

            3.3 为每个标签设置内容,当该标签被选中时将会打开内容所指定的活动;

        4. 将创建的标签加入到宿主内;

        5. 设置默认被选中的标签索引;


         运行后的结果如下图:


       



3.  实现TabHost.TabContentFactory接口


     TabHost类的内部接口TabContentFactory只拥有一个成员函数createTabContent(String tag),它是用来创建标签内容的回调函数。因此,实现TabContentFactory接口时需要实现createTabContent方法。


       现在,修改HelloWidget类,让它实现TabHost.TabContentFactory接口,并实现createTabContent方法。修改后的内容如下:


 

@SuppressWarnings("deprecation")public class HelloTabWidget extends TabActivity implements TabHost.TabContentFactory {   @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        final TabHost tabHost = getTabHost();        Resources res = getResources();        tabHost.addTab(tabHost.newTabSpec("tab1")                .setIndicator("tab1", res.getDrawable(R.drawable.ic_tab_artists))                .setContent(this));        tabHost.addTab(tabHost.newTabSpec("tab2")                .setIndicator("tab2", res.getDrawable(R.drawable.ic_tab_artists))                .setContent(this));        tabHost.addTab(tabHost.newTabSpec("tab3")                .setIndicator("tab3", res.getDrawable(R.drawable.ic_tab_artists))                .setContent(this));    }    /** {@inheritDoc} */    public View createTabContent(String tag) {        final TextView tv = new TextView(this);        tv.setText("I am " + tag);        return tv;    }}

       在新代码里需要注意以下几个方面:


                1.  代码中没有使用res/layout/下的布局文件;

                2.  为标签设置内容的方法使用的参数是"this",因为HelloWidget实现了TabHost.TabContentFactory;

                3.  createTabContent方法来自于TabHost.TabContentFactory接口,此方法返回一个View,恰是标签的内容;


       最后,运行程序的结果如下:



      



4.  把意图设置为标签内容


        

        首先,修改res/layout目录下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">    <LinearLayout        android:orientation="vertical"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:padding="5dp">        <TabWidget            android:id="@android:id/tabs"            android:layout_width="fill_parent"            android:layout_height="wrap_content" />        <FrameLayout            android:id="@android:id/tabcontent"            android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:padding="5dp" />    </LinearLayout></TabHost>

 

      

       为创建一个标签式布局,我们需要一个TabHostTabWidgetTabHost则必须是布局的根节点,该布局包括了一个用于显示标签的TabWidget和一个用于显示标签所承载内容的FrameLayoutFrameLayout 是每个标签内容显示的地方,现在是空的,因为TabHost会自动地把每个Activity嵌入其内。
       注意, TabWidgetFrameLayout 属性分别引用"@android:id/tabs"和"@android:id/tabcontent"作为他们的id。这两个平台内建组件id是为标签和标签内容专门准备的,目的是为了TabHost在需要时可以通过确切名字来取出TabWidgetFrameLayout,因此 ,这里必须这样写。

        同时,把LinearLayout属性里的orientation设置为“vertical”是为了将标签和其承载的内容“上下”排列。如果将orientation设置为“horizontal”,当切换标签时并不会看到它们所承载的内容。


       接下来,  在工程里创建三个独立的Activity类, 分别是ArtistsActivity, AlbumsActivity和SongsActivity。这些类分别代表了不同的三个标签。每个类的实现都很简单,只是显示一个简单的信息。例如:


public class ArtistsActivity extends Activity {    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        TextView textview = new TextView(this);        textview.setText("This is the Artists tab");        setContentView(textview);    }}

        

       当切换到该类所代表的标签时,则显示“This is the Artists tab”。还有,不要忘记将这三个类加入到清单文件里。


      接着,修改HelloWidget类,修改后如下:


@SuppressWarnings("deprecation")public class HelloTabWidget extends TabActivity  {    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);        setContentView(R.layout.main);        Resources res = getResources(); // Resource object to get Drawables        TabHost tabHost = getTabHost();  // The activity TabHost        TabHost.TabSpec spec;  // Resusable TabSpec for each tab        Intent intent;  // Reusable Intent for each tab        // Create an Intent to launch an Activity for the tab (to be reused)        intent = new Intent().setClass(this, ArtistsActivity.class);        // Initialize a TabSpec for each tab and add it to the TabHost        spec = tabHost.newTabSpec("artists").setIndicator("Artists",                          res.getDrawable(R.drawable.ic_tab_artists))                      .setContent(intent);        tabHost.addTab(spec);        // Do the same for the other tabs        intent = new Intent().setClass(this, AlbumsActivity.class);        spec = tabHost.newTabSpec("albums").setIndicator("Albums",                          res.getDrawable(R.drawable.ic_tab_artists))                      .setContent(intent);        tabHost.addTab(spec);        intent = new Intent().setClass(this, SongsActivity.class);        spec = tabHost.newTabSpec("songs").setIndicator("Songs",                          res.getDrawable(R.drawable.ic_tab_artists))                      .setContent(intent);        tabHost.addTab(spec);        tabHost.setCurrentTab(2);    }}
 

        

       在经过修改后,我们创建三个intent,并为每个intent关联了一个活动, 然后把intent设置为标签的内容。当在切换标签时,意图内关联的活动会被加载。值得注意的是,代码里可以不使用main.xml布局文件,程序的运行结果也不会有所差异。

        

       最后,  运行的结果如下:


         

 

        

        好了,在基于API 4(或以前)的平台版本上创建简单标签式布局的方法就介绍到这里。

 

                                                                                                                                                         2012年4月30日 晚毕。