这篇文章中我只讨论界面主题框架的实现,为了满足大多数人的需求,讲的比较基础。客户端是采用了目前比较流行的设计方式:

底部的tab菜单是总的导航,每点击一个tab将显示不同的内容。

一、主界面的实现

注意到上图中整个界面是三部分组成的actionbar、内容区域、以及底部tab选项卡。

actionbar部分只要设置成holo主题自然就会有,但是下面的内容区域和tab选项卡部分是这样布局的activity_main.xml:<?xml  version="1.0" encoding="utf-8"?>

android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
/>

其中内容区域是一个ViewPager,占满了除开actionbar和tab选项卡之外的所有内容。这是如何做到的呢?

这里面是一个高度写死了的布局。然后在ViewPager中,我们让

android:layout_height="0dip"
android:layout_weight="1"

就可以实现ViewPager自动占满。

这样上中下布局就实现了。

二、底部Tab效果的实现

底部tab就是上面提到的main_footer中包含的内容。

实现的思路

底部的tab切换效果我们是使用RadioGroup来实现的,使用RadioGroup的理由有如下几点:

(1)RadioGroup中的元素有state_checked、state_pressed、state_focused三种基本状态,可以在drawable中对这三种状态分别设置不同颜色或者图标。

(2)RadioGroup不同元素之间的state_checked状态是互斥的,当其中一个被选中其他的元素会自动变为未选中。

(3)RadioGroup自带对选中变化事件的监听:onCheckedChanged。

当然有一个理由阻止你选择RadioGroup,那就是RadioGroup默认的样式太难看(圆圈里面一个点),而你往往又不知道其实这种样式是可以轻易改变的:

只需一行xml代码就可以改变RadioGroup的默认样式:

android:button="@null"

因此tab部分我们就确定使用RadioGroup了

代码

下面是tab部分的xml代码:main_footer.xml<?xml  version="1.0" encoding="utf-8"?>

xmlns:netmoon="http://schemas.android.com/apk/res/cn.netmoon.netmoondevicemanager"
android:id="@+id/main_linearlayout_footer"
android:layout_width="fill_parent"
android:layout_height="55dip"
android:background="#33333333"
>
android:layout_width="fill_parent"
android:layout_height="wrap_content">

使用android:button="@null" android:drawableTop="@drawable/tab_blog" 两个属性可以去掉RadioButton的默认圆圈,同时为RadioButton增加一个图标。为什么不同的状态下图标可以呈现不同的颜色呢,请看tab_blog.xml的定义:<?xml  version="1.0" encoding="utf-8"?>

xmlns:android="http://schemas.android.com/apk/res/android">

tab_blog其实是一个selector,有三种状态,其中选中和获取焦点状态下图标为widget_bar_news_over.png,而未选中状态下图标为widget_bar_news_nor.png这两个图标只有一个区别,颜色不同。

同样的道理要使RadioButton的文字颜色不同我只需设置style属性:style="@style/GreenTabBar"

GreenTabBar.xml的定义(在values/style.xml中)

@drawable/green_tabbar_reverse_drawable

然后green_tabbar_reverse_drawable.xml 就是描述文字颜色的drawable了:<?xml  version="1.0" encoding="utf-8"?>

xmlns:android="http://schemas.android.com/apk/res/android">

可见设置文字颜色比设置图标多了一个步骤。green_tabbar_reverse_drawable.xml的状态要比之前描述图标的多了很多,其实应该以这个为准。

同样我们还可以设置不同状态下RadioButton的背景颜色(android:background="@drawable/***" ),就不赘述了。

三、监听选项卡切换事件并改变主内容区域

在MainActivity中实现的,下面是主要代码:

public class MainActivity extends FragmentActivity implements RadioGroup.OnCheckedChangeListener{
private RadioGroup mRadioGroup;
private ViewPager mPager;
private TabAdapter mAdapter;
private ArrayList mFragments;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPager = (ViewPager)findViewById(R.id.pager);
mRadioGroup  = (RadioGroup)findViewById(R.id.rg_tabs);
mRadioGroup.check(R.id.tab_blog);
mRadioGroup.setOnCheckedChangeListener(this);
mFragments = new ArrayList();
mFragments.add(new CategoryGridFragment());
mFragments.add(CodeListFragment.newInstance());
mFragments.add(new QuestionListFragment());
mFragments.add(new CategoryGridFragment());
mAdapter = new TabAdapter(getSupportFragmentManager(),mFragments);
mPager.setAdapter(mAdapter);
mPager.setOffscreenPageLimit(5);
}
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
switch (checkedId){
case R.id.tab_blog:
mPager.setCurrentItem(0,false);
break;
case R.id.tab_code:
mPager.setCurrentItem(1,false);
break;
case R.id.tab_ask:
mPager.setCurrentItem(2,false);
break;
}
}
}

通过mRadioGroup.setOnCheckedChangeListener(this); 我们将监听的任务交给了MainActivity自身,因此MainActivity必须实现onCheckedChanged方法。

在onCheckedChanged方法中,根据不同的选中状态,通过mPager.setCurrentItem来改变ViewPgaer显示的页,就改变了主内容区域的内容。

从上面的代码中还可以看到,ViewPager的每一个Page是一个Fragment,一个Fragment维护着一个界面。这几个Fragment分别是:CategoryGridFragment、CodeListFragment、QuestionListFragment、因为第四个界面还没有写好,第四个fragment暂时还是CategoryGridFragment。

在接下来的文章中我们将分别对这几个模块做介绍。