客户端开发之界面框架的实现
这篇文章中我只讨论界面主题框架的实现,为了满足大多数人的需求,讲的比较基础。客户端是采用了目前比较流行的设计方式:
底部的tab菜单是总的导航,每点击一个tab将显示不同的内容。
一、主界面的实现
注意到上图中整个界面是三部分组成的actionbar、内容区域、以及底部tab选项卡。
actionbar部分只要设置成holo主题自然就会有,但是下面的内容区域和tab选项卡部分是这样布局的activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
/>
<include layout="@layout/main_footer" />
</LinearLayout>
其中内容区域是一个ViewPager,占满了除开actionbar和tab选项卡之外的所有内容。这是如何做到的呢?
<include layout="@layout/main_footer
这里面是一个高度写死了的布局。然后在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"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<RadioGroup android:gravity="center_vertical" android:orientation="horizontal" android:id="@+id/rg_tabs" android:paddingTop="1.0dip" android:paddingRight="0.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true">
<RadioButton android:gravity="center" android:id="@+id/tab_blog" android:background="@drawable/bottom_tab_selector" android:paddingTop="4.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:button="@null" android:text="博客" android:drawableTop="@drawable/tab_blog" android:layout_weight="1.0" style="@style/GreenTabBar" />
<RadioButton android:gravity="center" android:id="@+id/tab_code" android:background="@drawable/bottom_tab_selector" android:paddingTop="4.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:button="@null" android:text="代码" android:drawableTop="@drawable/tab_code" android:layout_weight="1.0" style="@style/GreenTabBar" />
<RadioButton android:gravity="center" android:id="@+id/tab_ask" android:background="@drawable/bottom_tab_selector" android:paddingTop="4.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:button="@null" android:text="问答" android:drawableTop="@drawable/tab_ask" android:layout_weight="1.0" style="@style/GreenTabBar" />
<RadioButton android:gravity="center" android:id="@+id/tab_my" android:background="@drawable/bottom_tab_selector" android:paddingTop="4.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:button="@null" android:text="我的" android:drawableTop="@drawable/tab_my" android:layout_weight="1.0" style="@style/GreenTabBar" />
</RadioGroup>
</RelativeLayout>
</LinearLayout>
使用android:button="@null" android:drawableTop="@drawable/tab_blog" 两个属性可以去掉RadioButton的默认圆圈,同时为RadioButton增加一个图标。为什么不同的状态下图标可以呈现不同的颜色呢,请看tab_blog.xml的定义:
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="@drawable/widget_bar_news_nor" />
<item android:state_checked="true" android:drawable="@drawable/widget_bar_news_over" />
<item android:state_focused="true" android:drawable="@@drawable/widget_bar_news_over" />
</selector>
tab_blog其实是一个selector,有三种状态,其中选中和获取焦点状态下图标为widget_bar_news_over.png,而未选中状态下图标为widget_bar_news_nor.png这两个图标只有一个区别,颜色不同。
同样的道理要使RadioButton的文字颜色不同我只需设置style属性:style="@style/GreenTabBar"
GreenTabBar.xml的定义(在values/style.xml中)
<style name="GreenTabBar" parent="AppBaseTheme">
<item name="android:textColor">@drawable/green_tabbar_reverse_drawable</item>
</style>
然后green_tabbar_reverse_drawable.xml 就是描述文字颜色的drawable了:
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/green" />
<item android:state_pressed="true" android:color="@color/green" />
<item android:state_focused="true" android:color="@color/green" />
<item android:state_enabled="true" android:state_checked="false" android:color="@color/color_tabbar_text_gray" />
<item android:state_enabled="true" android:state_pressed="false" android:color="@color/color_tabbar_text_gray" />
<item android:state_focused="false" android:state_enabled="true" android:color="@color/color_tabbar_text_gray" />
<item android:state_enabled="false" android:state_checked="false" android:color="@color/color_gray" />
<item android:state_enabled="false" android:state_pressed="false" android:color="@color/color_gray" />
<item android:state_focused="false" android:state_enabled="false" android:color="@color/color_gray" />
</selector>
可见设置文字颜色比设置图标多了一个步骤。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<Fragment> 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<Fragment>();
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。
在接下来的文章中我们将分别对这几个模块做介绍。