本人水平有限,文章中如果出现什么不正确或者模糊的地方,还请各位小伙伴留下评论,多多指教 : )
这篇文章主要介绍多种方式实现主界面的tab,包括:
(1)使用Fragment实现
(2)使用ViewPage实现
(3)使用ViewPage+FragmentPageAdapter
(4)使用框架实现
在线的视频课程来自慕课网——多种多样的App主界面Tab实现方法。觉得文字不好理解的小伙伴可以去看视频,然后再回头自己敲一遍。
比较常规的使用方法,需要大家对Fragment有基本了解,这里推荐hongyang大神的几篇博文:
Android Fragment 真正的完全解析(上)
Android Fragment 真正的完全解析(下)
相信各位看完之后对Fragment就能有一个比较清楚的了解。
这种方式实现的思路比较简单:
1、首先在主布局中加入FragmentLayout
2、然后在Java代码中监听底部的按钮,当点击时,只需让FragmentLayout加载相应的Fragment即可
可以看到,如果单纯地使用Fragment,实际上是不能实现左右滑动的效果,页面的切换,只能靠点击底部的Button来实现。
首先是底部的一个布局文件bottom.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="65dp"
android:background="@drawable/bottom_bar">
<LinearLayout
android:id="@+id/id_tab_weixin"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_weixin_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_weixin_pressed"
android:background="#0000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:text="微信"/>
LinearLayout>
<LinearLayout
android:id="@+id/id_tab_frd"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_frd_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_find_frd_normal"
android:background="#0000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:text="朋友"/>
LinearLayout>
<LinearLayout
android:id="@+id/id_tab_address"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_address_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_address_normal"
android:background="#0000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:text="通讯录"/>
LinearLayout>
<LinearLayout
android:id="@+id/id_tab_setting"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_setting_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_settings_normal"
android:background="#0000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:text="设置"/>
LinearLayout>
LinearLayout>
简单的线性布局,放置我们的按钮。
这个布局在后面的栗子中也会使用。
接下来是一个顶部的title
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="45dp"
android:gravity="center"
android:background="@drawable/title_bar">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="微信"
android:textColor="#ffffff"
android:textSize="20sp"
android:textStyle="bold"
android:layout_gravity="center"/>
LinearLayout>
就一个TextView。
为了简单起见,这里面的布局只放置一个TextView
TestActivity2
public class TestActivity2 extends Activity implements View.OnClickListener {
private LinearLayout mTabWeixin;
private LinearLayout mTabFrd;
private LinearLayout mTabAddress;
private LinearLayout mTabSetting;
//底部的按钮
private ImageButton mWeiXin;
private ImageButton mFriend;
private ImageButton mAddress;
private ImageButton mSetting;
//FragmentLayout要加载的四个Fragment
private WeiXinFragment weiXinFragment;
private FriendFragment friendFragment;
private AddressFragment addressFragment;
private SettingFragment settingFragment;
//顶部的标题
private TextView tvTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.test_ac_2);
initView();
initEvents();
setSelect(0);
}
private void initEvents() {
mWeiXin.setOnClickListener(this);
mFriend.setOnClickListener(this);
mAddress.setOnClickListener(this);
mSetting.setOnClickListener(this);
}
private void initView() {
//初始化
mTabWeixin= (LinearLayout) findViewById(R.id.id_tab_weixin);
mTabFrd= (LinearLayout) findViewById(R.id.id_tab_frd);
mTabAddress= (LinearLayout) findViewById(R.id.id_tab_address);
mTabSetting= (LinearLayout) findViewById(R.id.id_tab_setting);
mWeiXin= (ImageButton) findViewById(R.id.id_tab_weixin_img);
mFriend= (ImageButton) findViewById(R.id.id_tab_frd_img);
mAddress= (ImageButton) findViewById(R.id.id_tab_address_img);
mSetting= (ImageButton) findViewById(R.id.id_tab_setting_img);
tvTitle= (TextView) findViewById(R.id.tv_title);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.id_tab_weixin_img:
setSelect(0);
break;
case R.id.id_tab_frd_img:
setSelect(1);
break;
case R.id.id_tab_address_img:
setSelect(2);
break;
case R.id.id_tab_setting_img:
setSelect(3);
break;
}
}
private void hideFragment(FragmentTransaction fragmentTransaction) {
if (weiXinFragment!=null){
fragmentTransaction.hide(weiXinFragment);
}
if (friendFragment!=null){
fragmentTransaction.hide(friendFragment);
}
if (addressFragment!=null){
fragmentTransaction.hide(addressFragment);
}
if (settingFragment!=null){
fragmentTransaction.hide(settingFragment);
}
}
/*
* 重置所有的图片,让其恢复到灰色状态
* */
private void resetImage() {
mSetting.setImageResource(R.drawable.tab_settings_normal);
mWeiXin.setImageResource(R.drawable.tab_weixin_normal);
mAddress.setImageResource(R.drawable.tab_address_normal);
mFriend.setImageResource(R.drawable.tab_find_frd_normal);
}
/*
* 设置某个Fragment
* */
private void setSelect(int i){
FragmentManager fm=getFragmentManager();
FragmentTransaction fragmentTransaction=fm.beginTransaction();
//重置图片状态
resetImage();
hideFragment(fragmentTransaction);
switch (i){
case 0:
//设置标题
tvTitle.setText("微信");
if (weiXinFragment==null){
//如果Fragment还没实例化,实例化,并在fragmentTransaction中添加
weiXinFragment=new WeiXinFragment();
fragmentTransaction.add(R.id.id_content,weiXinFragment);
}else{
//如果已经实例化了,就显示
fragmentTransaction.show(weiXinFragment);
}
fragmentTransaction.commit();
//改变底部图标的状态
mWeiXin.setImageResource(R.drawable.tab_weixin_pressed);
break;
case 1:
tvTitle.setText("朋友");
if (friendFragment==null){
friendFragment=new FriendFragment();
fragmentTransaction.add(R.id.id_content,friendFragment);
}else{
fragmentTransaction.show(friendFragment);
}
fragmentTransaction.commit();
mFriend.setImageResource(R.drawable.tab_find_frd_pressed);
break;
case 2:
tvTitle.setText("通讯录");
if (addressFragment==null){
addressFragment=new AddressFragment();
fragmentTransaction.add(R.id.id_content,addressFragment);
}else{
fragmentTransaction.show(addressFragment);
}
fragmentTransaction.commit();
mAddress.setImageResource(R.drawable.tab_address_pressed);
break;
case 3:
tvTitle.setText("设置");
if (settingFragment==null){
settingFragment=new SettingFragment();
fragmentTransaction.add(R.id.id_content,settingFragment);
}else{
fragmentTransaction.show(settingFragment);
}
fragmentTransaction.commit();
mSetting.setImageResource(R.drawable.tab_settings_pressed);
break;
}
}
}
代码逻辑很清楚,中间需要提醒的地方已经用注释表明,这个小栗子其实就是Fragment的常规使用,涉及到的内容也都是Fragment基础知识,需要各位小伙伴烂熟于心。
在上一个栗子当中,我们使用的是FragmentLayout来作为填充Fragment的容器。当使用ViewPage,我们需要把布局文件中的Layout替换成ViewPager。这就要求开发者对ViewPager的使用有基本的了解。
可以看到使用了ViewPager之后不仅可以实现左右的滑动,而且还能通过底部的点击来实现页面切换的效果
首先是布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/top"/>
<android.support.v4.view.ViewPager
android:id="@+id/id_viewpager"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp">
android.support.v4.view.ViewPager>
<include
layout="@layout/bottom"/>
LinearLayout>
非常简单,就是把中间的FragmentLayout换成了ViewPager。
重点在于接下里的Java代码当中,里面涉及到了ViewPager的基本使用。
public class TestActivity1 extends Activity implements View.OnClickListener {
private ViewPager viewPager;
private PagerAdapter pagerAdapter;
private List mViews =new ArrayList<>();
private FragmentPagerAdapter fragmentPagerAdapter;
private FragmentStatePagerAdapter fragmentStatePagerAdapter;
private LinearLayout mTabWeixin;
private LinearLayout mTabFrd;
private LinearLayout mTabAddress;
private LinearLayout mTabSetting;
private ImageButton mWeiXin;
private ImageButton mFriend;
private ImageButton mAddress;
private ImageButton mSetting;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.test_ac_1);
initView();
initEvents();
}
/*
* 初始化事件
* */
private void initEvents() {
mWeiXin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
viewPager.setCurrentItem(0);
mWeiXin.setImageResource(R.drawable.tab_weixin_pressed);
}
});
mSetting.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
viewPager.setCurrentItem(3);
mSetting.setImageResource(R.drawable.tab_settings_pressed);
}
});
mAddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
viewPager.setCurrentItem(2);
mAddress.setImageResource(R.drawable.tab_address_pressed);
}
});
mFriend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
viewPager.setCurrentItem(1);
mFriend.setImageResource(R.drawable.tab_find_frd_pressed);
}
});
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int currentItem =viewPager.getCurrentItem();
resetImage();
switch (currentItem){
case 0:
mWeiXin.setImageResource(R.drawable.tab_weixin_pressed);
break;
case 1:
mFriend.setImageResource(R.drawable.tab_find_frd_pressed);
break;
case 2:
mAddress.setImageResource(R.drawable.tab_address_pressed);
break;
case 3:
mSetting.setImageResource(R.drawable.tab_settings_pressed);
break;
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void initView() {
//初始化
viewPager= (ViewPager) findViewById(R.id.id_viewpager);
mTabWeixin= (LinearLayout) findViewById(R.id.id_tab_weixin);
mTabFrd= (LinearLayout) findViewById(R.id.id_tab_frd);
mTabAddress= (LinearLayout) findViewById(R.id.id_tab_address);
mTabSetting= (LinearLayout) findViewById(R.id.id_tab_setting);
mWeiXin= (ImageButton) findViewById(R.id.id_tab_weixin_img);
mFriend= (ImageButton) findViewById(R.id.id_tab_frd_img);
mAddress= (ImageButton) findViewById(R.id.id_tab_address_img);
mSetting= (ImageButton) findViewById(R.id.id_tab_setting_img);
LayoutInflater mLayoutInfater=LayoutInflater.from(this);
View view1=mLayoutInfater.inflate(R.layout.tab01,null);
View view2=mLayoutInfater.inflate(R.layout.tab02,null);
View view3=mLayoutInfater.inflate(R.layout.tab03,null);
View view4=mLayoutInfater.inflate(R.layout.tab04,null);
mViews.add(view1);
mViews.add(view2);
mViews.add(view3);
mViews.add(view4);
pagerAdapter=new PagerAdapter() {
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view=mViews.get(position);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mViews.get(position));
}
@Override
public int getCount() {
return mViews.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
};
viewPager.setAdapter(pagerAdapter);
}
@Override
public void onClick(View view) {
Log.d("--tab--","tab click");
//重置所有的图片
resetImage();
switch (view.getId()){
case R.id.id_tab_weixin:
viewPager.setCurrentItem(0);
mWeiXin.setImageResource(R.drawable.tab_weixin_pressed);
Log.d("--tab--","tab weixin");
break;
case R.id.id_tab_frd:
viewPager.setCurrentItem(1);
mFriend.setImageResource(R.drawable.tab_find_frd_pressed);
Log.d("--tab--","tab friend");
break;
case R.id.id_tab_address:
viewPager.setCurrentItem(2);
mAddress.setImageResource(R.drawable.tab_address_pressed);
Log.d("--tab--","tab address");
break;
case R.id.id_tab_setting:
viewPager.setCurrentItem(3);
mSetting.setImageResource(R.drawable.tab_settings_pressed);
Log.d("--tab--","tab setting");
break;
}
}
/*
* 让所有的图片都变暗
* */
private void resetImage() {
mSetting.setImageResource(R.drawable.tab_settings_normal);
mWeiXin.setImageResource(R.drawable.tab_weixin_normal);
mAddress.setImageResource(R.drawable.tab_address_normal);
mFriend.setImageResource(R.drawable.tab_find_frd_normal);
}
}
同ViewPager实现相同
同ViewPager实现相同
既然这种方式使用的思路和效果和直接使用ViewPager的相同,那么采用FragmenAdapter的方式来实现Tab页面切换有什么好处呢?
首先单纯使用ViewPager时,里面的View是通过LayoutInfater装载进去的,虽然也能够实现和和采用FragmentPagerAdapter一样的效果,但是如果这么做,必然所有的逻辑控制都放在MainActivity当中,对于后期代码的维护十分不利。
使用FragmentPagerAdapter的好处之一就是能够使得当前页面的逻辑处理仅有当前Fragment来承担,相当于把MainActivity里面的事件逻辑分派给了Fragment来处理。这个优点,其实在使用Fragment的时候也能体现出来。
所以说,如果仅仅是页面的展示(如图片轮播),直接使用ViewPager就好了,但如果ViewPager的每个页面中包含比较复杂的逻辑,就应该使用ViewPager+FragmentPagerAdapter的方式来完成Tab页面的切换。
xml与ViewPager实现的相同,不再重复。
Java代码:
public class TestActivity3 extends FragmentActivity implements View.OnClickListener {
private ViewPager viewPager;
private FragmentPagerAdapter mAdapter;
private List fragments;
private LinearLayout mTabWeixin;
private LinearLayout mTabFrd;
private LinearLayout mTabAddress;
private LinearLayout mTabSetting;
private ImageButton mWeiXin;
private ImageButton mFriend;
private ImageButton mAddress;
private ImageButton mSetting;
private int select;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.test_ac_3);
initView();
initEvent();
}
private void initEvent() {
mWeiXin.setOnClickListener(this);
mFriend.setOnClickListener(this);
mAddress.setOnClickListener(this);
mSetting.setOnClickListener(this);
}
private void initView() {
//初始化
viewPager= (ViewPager) findViewById(R.id.id_viewpager3);
mTabWeixin= (LinearLayout) findViewById(R.id.id_tab_weixin);
mTabFrd= (LinearLayout) findViewById(R.id.id_tab_frd);
mTabAddress= (LinearLayout) findViewById(R.id.id_tab_address);
mTabSetting= (LinearLayout) findViewById(R.id.id_tab_setting);
mWeiXin= (ImageButton) findViewById(R.id.id_tab_weixin_img);
mFriend= (ImageButton) findViewById(R.id.id_tab_frd_img);
mAddress= (ImageButton) findViewById(R.id.id_tab_address_img);
mSetting= (ImageButton) findViewById(R.id.id_tab_setting_img);
fragments=new ArrayList<>();
WeiXinFragment weiXinFragment=new WeiXinFragment();
FriendFragment friendFragment=new FriendFragment();
AddressFragment addressFragment=new AddressFragment();
SettingFragment settingFragment=new SettingFragment();
fragments.add(weiXinFragment);
fragments.add(friendFragment);
fragments.add(addressFragment);
fragments.add(settingFragment);
mAdapter=new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
};
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
resetImage();
switch (position){
case 0:
mWeiXin.setImageResource(R.drawable.tab_weixin_pressed);
viewPager.setCurrentItem(0);
break;
case 1:
mFriend.setImageResource(R.drawable.tab_find_frd_pressed);
viewPager.setCurrentItem(1);
break;
case 2:
mAddress.setImageResource(R.drawable.tab_address_pressed);
viewPager.setCurrentItem(2);
break;
case 3:
mSetting.setImageResource(R.drawable.tab_settings_pressed);
viewPager.setCurrentItem(3);
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
public void onClick(View view) {
resetImage();
switch (view.getId()) {
case R.id.id_tab_weixin_img:
setSelect(0);
break;
case R.id.id_tab_frd_img:
setSelect(1);
break;
case R.id.id_tab_address_img:
setSelect(2);
break;
case R.id.id_tab_setting_img:
setSelect(3);
break;
}
}
public void setSelect(int select) {
switch (select){
case 0:
mWeiXin.setImageResource(R.drawable.tab_weixin_pressed);
viewPager.setCurrentItem(0);
break;
case 1:
mFriend.setImageResource(R.drawable.tab_find_frd_pressed);
viewPager.setCurrentItem(1);
break;
case 2:
mAddress.setImageResource(R.drawable.tab_address_normal);
viewPager.setCurrentItem(2);
break;
case 3:
mSetting.setImageResource(R.drawable.tab_settings_pressed);
viewPager.setCurrentItem(3);
break;
}
}
private void resetImage() {
mSetting.setImageResource(R.drawable.tab_settings_normal);
mWeiXin.setImageResource(R.drawable.tab_weixin_normal);
mAddress.setImageResource(R.drawable.tab_address_normal);
mFriend.setImageResource(R.drawable.tab_find_frd_normal);
}
}
如果每一次在开发的过程当中都去写一个这样的Tab页面,无疑耗时耗力,当然,对于初学者而言,这种“耗时耗力”能够帮助他们了解效果实现的基本实现原理。
在这里推荐给大家一款比较不错的ViewPager框架:
LuckyJayce/ViewPagerIndicator
里面的介绍比较详细,这里就不多讲了,对这个框架感兴趣的小伙伴可以去github上仔细研读一下~
最后附上下载的源码:github