漫谈android开发之菜单(二)
版本二:
版本一的原料是LinearLayout+Buttons+LayoutInflater.我们可以想到,“互斥”这一属性明显就是由RadioButton代言。所以这个版本咱们将RadioButton加入。布局文件大致上不变,修改下RadioButton和加入RadioGroup就OK。逻辑方面,需要实现OnCheckedChangeListener接口。同时,背景图片的改变咱们这里用selector代替。布局代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> <RadioGroup android:id="@+id/rb_group" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <RadioButton android:id="@+id/rb_0" android:checked="true" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_index_selector"/> <RadioButton android:id="@+id/rb_1" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_home_selector"/> <RadioButton android:id="@+id/rb_2" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_wt_selector"/> <RadioButton android:id="@+id/rb_3" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_yh_selector"/> </RadioGroup> </LinearLayout> </TabHost>
selector需要在drawable下实现一个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/bst_tab_home_0" /> <item android:state_checked="true" android:drawable="@drawable/bst_tab_home_1" /> </selector>
在onCheckedChanged中,需要注意一点的是,不要忘记判断当前RadioButton是否被点击。因为onCheckedChanged记录的是点击状态改变的RadioButton,因此每次点击事件会有两个RadioButton的状态发生改变,分别是由选中到未选中、由未选中到选中。所以如果只需要获取被点击的那个RadioButton的话,建议在代码最外层加一个if判断。代码如下:
package com.example.menutest; import android.app.Activity; import android.app.TabActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TabHost; import android.widget.TabHost.TabContentFactory; public class MenuRbActivity extends Activity implements OnCheckedChangeListener{ private RadioGroup radioGroup; private RadioButton rbHd,rbHome,rbWt,rbYh; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_rb); initViews(); } private void initViews() { // TODO Auto-generated method stub //Initialize RadioGroup and RadioButtons radioGroup = (RadioGroup) findViewById(R.id.rb_group); rbHd = (RadioButton) findViewById(R.id.rb_0); rbHd.setOnCheckedChangeListener(this); rbHome = (RadioButton) findViewById(R.id.rb_1); rbHome.setOnCheckedChangeListener(this); rbWt = (RadioButton) findViewById(R.id.rb_2); rbWt.setOnCheckedChangeListener(this); rbYh = (RadioButton) findViewById(R.id.rb_3); rbYh.setOnCheckedChangeListener(this); } @Override public void onCheckedChanged(CompoundButton bv, boolean isChecked) { // TODO Auto-generated method stub if(isChecked) switch(bv.getId()){ case R.id.rb_0: rbHd.setChecked(true); //设置第一个选项的内容break; case R.id.rb_1: rbHd.setChecked(true); //设置第二个选项的内容break; case R.id.rb_2: rbHd.setChecked(true);break; case R.id.rb_3: rbHd.setChecked(true);break; } } }
版本二的选项区做了改变。然后内容区依旧选择使用LayoutInflater.
版本三:
以上两个版本我们完成了选项区的改变,使用RadioButton已经比较接近现在大部分程序员的开发习惯。
那么内容区,虽然LayoutInflater可以比较简单的实现View的贴入,但是就代码来说,比较冗余和繁杂。这时,一个我们熟悉的老朋友闪亮登场,TabHost.。
TabHost的实现和前两个版本的LayoutInflater差不多。区别点在于,TabHost的每一个内容View要么是布局都写在同一个文件中——这样就不需要LayoutInflater,我估计底层使用的是类似findViewById()方法。(有知道的朋友请说一下。)要么就是把每个内容View的布局写在不同的布局文件中,那么,这个就是使用的LayoutInflater。
另外,TabHost的好处是,google将这些封装了起来(你看不见LayoutInflater)。所以代码上结构性强,可观赏性有所提升。
下面是RadioButton+TabHost的代码:
<TabHost xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom"> <RadioGroup android:id="@+id/rb_group" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <RadioButton android:id="@+id/rb_0" android:checked="true" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_index_selector"/> <RadioButton android:id="@+id/rb_1" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_home_selector"/> <RadioButton android:id="@+id/rb_2" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_wt_selector"/> <RadioButton android:id="@+id/rb_3" android:layout_width="0dp" android:layout_height="match_parent" android:button="@null" android:layout_weight="1" android:background="@drawable/tab_yh_selector"/> </RadioGroup> </TabWidget> </LinearLayout> </TabHost>
布局文件就是加入了TabHost,需要注意的是,如果你继承TabActivity,然后使用了默认的setContentView(),就必须要有tabhost、tabcontent、tabs等存在,分别有对应的组件。设置Id时是@android:id/tabcontent,这是因为这几个id都是android本身拥有的,不需要+id.
package com.example.menutest; import android.app.TabActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.RadioButton; import android.widget.TabHost; public class MenuRbActivity extends TabActivity implements OnCheckedChangeListener{ private RadioButton rbHd,rbHome,rbWt,rbYh; private TabHost mTabHost; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_rb); initViews(); } private void initViews() { // TODO Auto-generated method stub //Initialize RadioGroup and RadioButtons rbHd = (RadioButton) findViewById(R.id.rb_0); rbHd.setOnCheckedChangeListener(this); rbHome = (RadioButton) findViewById(R.id.rb_1); rbHome.setOnCheckedChangeListener(this); rbWt = (RadioButton) findViewById(R.id.rb_2); rbWt.setOnCheckedChangeListener(this); rbYh = (RadioButton) findViewById(R.id.rb_3); rbYh.setOnCheckedChangeListener(this); //Initialize TabHost mTabHost = getTabHost(); mTabHost.addTab(mTabHost.newTabSpec("0").setIndicator("").setContent(new Intent(MenuRbActivity.this,Tab0Activity.class))); mTabHost.addTab(mTabHost.newTabSpec("1").setIndicator("").setContent(new Intent(MenuRbActivity.this,Tab1Activity.class))); mTabHost.addTab(mTabHost.newTabSpec("2").setIndicator("").setContent(new Intent(MenuRbActivity.this,Tab2Activity.class))); mTabHost.addTab(mTabHost.newTabSpec("3").setIndicator("").setContent(new Intent(MenuRbActivity.this,Tab3Activity.class))); //let view tab0 be showed at first mTabHost.setCurrentTab(0); } @Override public void onCheckedChanged(CompoundButton bv, boolean isChecked) { // TODO Auto-generated method stub if(isChecked) switch(bv.getId()){ case R.id.rb_0: rbHd.setChecked(true); mTabHost.setCurrentTab(0); break; case R.id.rb_1: rbHd.setChecked(true); mTabHost.setCurrentTab(1); break; case R.id.rb_2: rbHd.setChecked(true); mTabHost.setCurrentTab(2); break; case R.id.rb_3: rbHd.setChecked(true); mTabHost.setCurrentTab(3); break; } } }
逻辑上基本就是版本二的内容。
版本三基本就完成了一般的tab架构。RadioButton+TabHost也是一个比较普遍使用的菜单。那么我们可不可以给这个菜单加上滑动切换View呢?这个得等到下一个版本再说了。