Android底部tab切换界面的实现比较简单,可以利用TabHost直接实现,实现方式网上资源很多。那么除了用特定的组件来实现tab外能不能自己写代码实现呢。答案是肯定的。还有一个很常用的问题,就是不同的tab界面能否实现不同的标题栏?这个需求在项目中经常碰到,本文将讲叙Android底部tab切换界面的实现以及它与标题栏的结合。实现效果图如下:
上图就是我们要实现的效果图,切换到不同的界面有不同的显示标题。不多说直接上代码。
首先当然是布局文件,先实现标题栏布局。新建title.xml文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="48dp" android:background="#111111" > <TextView android:id="@+id/title_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:textColor="#ffffff" android:textSize="18dp" android:visibility="gone" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="#ffffff" android:textSize="22dp"/> <TextView android:id="@+id/title_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:textColor="#ffffff" android:textSize="18dp" android:visibility="gone" /> </RelativeLayout>
以上实现了标题栏的布局,title_left和title_right分别是标题栏的左、右按钮,默认情况下将其设置为不可见。
接下来就是tab栏布局文件的实现,新建一个tab.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_bottom" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="#efefef" android:orientation="horizontal" > <LinearLayout android:id="@+id/nav_search" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:orientation="vertical" > <View android:id="@+id/nav_search_color" android:layout_width="fill_parent" android:layout_height="3dp" android:background="@color/nav_pressed" android:duplicateParentState="true" /> <ImageView android:id="@+id/nav_search_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="3dp" android:scaleType="center" android:src="@drawable/icon_square_nor1" /> <TextView android:id="@+id/nav_search_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="搜 索" android:textColor="@color/nav_pressed" android:textSize="10sp" /> </LinearLayout> <LinearLayout android:id="@+id/nav_home_layout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:orientation="vertical" > <View android:id="@+id/nav_home_color" android:layout_width="fill_parent" android:layout_height="3dp" android:background="@color/nav_normal" /> <ImageView android:id="@+id/nav_home_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="3dp" android:scaleType="center" android:src="@drawable/icon_home_nor" /> <TextView android:id="@+id/nav_home_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="主 页" android:textColor="@color/nav_text_normal" android:textSize="10sp" /> </LinearLayout> <LinearLayout android:id="@+id/nav_selfinfo_layout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:orientation="vertical" > <View android:id="@+id/nav_selfinfo_color" android:layout_width="fill_parent" android:layout_height="3dp" android:background="@color/nav_normal" /> <ImageView android:id="@+id/nav_selfinfo_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="3dp" android:scaleType="center" android:src="@drawable/icon_selfinfo_nor" /> <TextView android:id="@+id/nav_selfinfo_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="个人信息" android:textColor="@color/nav_text_normal" android:textSize="10sp" /> </LinearLayout> <LinearLayout android:id="@+id/nav_mess_layout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:orientation="vertical" > <View android:id="@+id/nav_mess_color" android:layout_width="fill_parent" android:layout_height="3dp" android:background="@color/nav_normal" /> <ImageView android:id="@+id/nav_mess_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="3dp" android:scaleType="center" android:src="@drawable/icon_meassage_nor" /> <TextView android:id="@+id/nav_mess_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="3dp" android:gravity="center_horizontal" android:text="信 息" android:textColor="@color/nav_text_normal" android:textSize="10sp" /> </LinearLayout> </LinearLayout>
只需要看一部分就可以了,一个LinearLayout包括着一个View,ImageView和TextView,其中View是底部栏上方的那条横线。ImagView与TextView不用说,就是底部栏的头像和头像下方的文字。
主布局文件就是利用include把标题栏与底部栏融合到一起,并用ViewPage来显示不同页面。布局如下:
<RelativeLayout 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" tools:context=".MainActivity" > <include android:id="@+id/top" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" layout="@layout/title" /> <include android:id="@+id/tab" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" layout="@layout/tab" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/top" android:layout_above="@id/tab" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" > </android.support.v4.view.ViewPager> </LinearLayout> </RelativeLayout>
接下来的实现我们用到了Fragment,四个页面分别加载了四个Fragment。所以要写四个不同的fragment.xml,这个根据不同需求进行编写。那重头戏来了,下面贴出主程序。代码有点长,但不用担心,其实现原理很简单。
public class MainActivity extends FragmentActivity { private ViewPager m_vp; private int navIndex = 0; private int currIndex = 0; private Fragment mfragment1; private Fragment mfragment2; private Fragment mfragment3; private Fragment mfragment4; private List<Fragment> fragmentList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initTitle(); getView(); initFragments(); } /** * 初始化标题,并加载四个Fragment */ public void initTitle(){ ((TextView) findViewById(R.id.title)).setText("搜索"); ((TextView)findViewById(R.id.title_left)).setVisibility(View.INVISIBLE); ((TextView)findViewById(R.id.title_right)).setVisibility(View.INVISIBLE); } private void getView(){ m_vp = (ViewPager)findViewById(R.id.viewpager); mfragment1 = new Fragment1(); mfragment2 = new Fragment2(); mfragment3 = new Fragment3(); mfragment4 = new Fragment4(); } /** * 初始化页面 */ public void initFragments() { fragmentList = new ArrayList<Fragment>(); fragmentList.add(mfragment1); fragmentList.add(mfragment2); fragmentList.add(mfragment3); fragmentList.add(mfragment4); findViewById(R.id.nav_search).setOnClickListener(new MyOnClickListener(0)); findViewById(R.id.nav_home_layout).setOnClickListener(new MyOnClickListener(1)); findViewById(R.id.nav_selfinfo_layout).setOnClickListener(new MyOnClickListener(2)); findViewById(R.id.nav_mess_layout).setOnClickListener(new MyOnClickListener(3)); setNavState(navIndex, 0); m_vp.setAdapter(new MyViewPagerAdapter(getSupportFragmentManager())); m_vp.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int arg0) { Log.i("zhi", arg0+""); switch (arg0) { case 0: if (navIndex != 0){ // 点击之前如果就是这个控件,不变化 setNavState(navIndex, 0); navIndex = 0; } break; case 1: if (navIndex != 1){ // 点击之前如果就是这个控件,不变化 setNavState(navIndex, 1); navIndex = 1; } break; case 2: if (navIndex != 2){ // 点击之前如果就是这个控件,不变化 setNavState(navIndex, 2); navIndex = 2; } break; case 3: if (navIndex != 3){ // 点击之前如果就是这个控件,不变化 setNavState(navIndex, 3); navIndex = 3; } break; default: break; } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { } }); } private void setNavState(int before, int after) { // 点击之前的那个按钮恢复正常 switch (before) { case 0: findViewById(R.id.nav_search_color).setBackgroundResource(R.color.nav_normal); ((ImageView )findViewById(R.id.nav_search_img)).setImageResource(R.drawable.icon_square_nor); ((TextView) findViewById(R.id.nav_search_text)).setTextColor(getResources().getColor(R.color.nav_text_normal)); break; case 1: findViewById(R.id.nav_home_color).setBackgroundResource(R.color.nav_normal); ((ImageView )findViewById(R.id.nav_home_img)).setImageResource(R.drawable.icon_home_nor); ((TextView) findViewById(R.id.nav_home_text)).setTextColor(getResources().getColor(R.color.nav_text_normal)); ((TextView)findViewById(R.id.title_right)).setVisibility(View.INVISIBLE); break; case 2: findViewById(R.id.nav_selfinfo_color).setBackgroundResource(R.color.nav_normal); ((ImageView )findViewById(R.id.nav_selfinfo_img)).setImageResource(R.drawable.icon_selfinfo_nor); ((TextView) findViewById(R.id.nav_selfinfo_text)).setTextColor(getResources().getColor(R.color.nav_text_normal)); ((TextView)findViewById(R.id.title_left)).setVisibility(View.INVISIBLE); break; case 3: findViewById(R.id.nav_mess_color).setBackgroundResource(R.color.nav_normal); ((ImageView )findViewById(R.id.nav_mess_img)).setImageResource(R.drawable.icon_meassage_nor); ((TextView) findViewById(R.id.nav_mess_text)).setTextColor(getResources().getColor(R.color.nav_text_normal)); break; default: break; } // 点击到的那个显示状态 switch (after) { case 0: findViewById(R.id.nav_search_color).setBackgroundResource(R.color.nav_pressed); ((ImageView )findViewById(R.id.nav_search_img)).setImageResource(R.drawable.icon_square_nor1); ((TextView) findViewById(R.id.nav_search_text)).setTextColor(getResources().getColor(R.color.nav_text_pressed)); ((TextView) findViewById(R.id.title)).setText("搜索"); break; case 1: findViewById(R.id.nav_home_color).setBackgroundResource(R.color.nav_pressed); ((ImageView )findViewById(R.id.nav_home_img)).setImageResource(R.drawable.icon_home_nor1); ((TextView) findViewById(R.id.nav_home_text)).setTextColor(getResources().getColor(R.color.nav_text_pressed)); ((TextView)findViewById(R.id.title_right)).setVisibility(View.VISIBLE); ((TextView)findViewById(R.id.title_right)).setText("设置"); ((TextView) findViewById(R.id.title)).setText("主页"); break; case 2: findViewById(R.id.nav_selfinfo_color).setBackgroundResource(R.color.nav_pressed); ((ImageView )findViewById(R.id.nav_selfinfo_img)).setImageResource(R.drawable.icon_selfinfo_sel1); ((TextView) findViewById(R.id.nav_selfinfo_text)).setTextColor(getResources().getColor(R.color.nav_text_pressed)); ((TextView)findViewById(R.id.title_left)).setVisibility(View.VISIBLE); ((TextView)findViewById(R.id.title_left)).setText("返回"); ((TextView) findViewById(R.id.title)).setText("个人信息"); break; case 3: findViewById(R.id.nav_mess_color).setBackgroundResource(R.color.nav_pressed); ((ImageView )findViewById(R.id.nav_mess_img)).setImageResource(R.drawable.icon_meassage_nor1); ((TextView) findViewById(R.id.nav_mess_text)).setTextColor(getResources().getColor(R.color.nav_text_pressed)); ((TextView) findViewById(R.id.title)).setText("信息"); break; default: break; } } public class MyViewPagerAdapter extends FragmentPagerAdapter{ public MyViewPagerAdapter(FragmentManager fm) { super(fm); // TODO Auto-generated constructor stub } @Override public Fragment getItem(int arg0) { return fragmentList.get(arg0); } @Override public int getCount() { return fragmentList.size(); } } public class MyOnClickListener implements View.OnClickListener { private int index = 0; public MyOnClickListener(int i) { index = i; currIndex=i; } @Override public void onClick(View v) { m_vp.setCurrentItem(index); } }; }
相信大家都能看懂,这里简单讲解一下。程序首先运行initTitle对标题栏进行初始化,在getView中定义一个list装上四个Fragment,方便之后的调用。initFragments()方法主要是完成对界面的加载和监听不到的触发事件。这里用到了Viewpage进行页面的切换。首先是监听底部栏按钮的的点击事件,点击的按钮触发ViewPage的setCurrentItem方法加载不同的ViewPage页。ViewPage对页面的变化进行监听,不同页面调用不同的setNavState()方法。最后就只剩下了解setNavState的作用了。setNavState方法用于对底部按钮的图标、字体状态还有标题栏的显示状态进行动态变化,switch(before)是操作之前点击的那个按钮的状态,switch(after)是操作之后点击的按钮的状态。
到这里主函数就讲完了。接下来要做是的就定义自己的Fragement,让它们去实现我们想要的界面。至此我们一个自定义的底tab界面就完成了。是不是很简单。以下我贴出源代码,下载不用积分,只希望对大家有点帮助。
代码下载