本人水平有限,文章中如果出現甚么不正確或模糊的地方,還請各位小火伴留下評論,多多指教 : )
這篇文章主要介紹多種方式實現主界面的tab,包括:
(1)使用Fragment實現
(2)使用ViewPage實現
(3)使用ViewPage+FragmentPageAdapter
(4)使用框架實現
在線的視頻課程來自慕課網——多種多樣的App主界面Tab實現方法。覺得文字不好理解的小火伴可以去看視頻,然后再回頭自己敲1遍。
比較常規的使用方法,需要大家對Fragment有基本了解,這里推薦hongyang大神的幾篇博文:
Android Fragment 真實的完全解析(上)
Android Fragment 真實的完全解析(下)
相信各位看完以后對Fragment就可以有1個比較清楚的了解。
這類方式實現的思路比較簡單:
1、首先在主布局中加入FragmentLayout
2、然后在Java代碼中監聽底部的按鈕,當點擊時,只需讓FragmentLayout加載相應的Fragment便可
可以看到,如果單純地使用Fragment,實際上是不能實現左右滑動的效果,頁面的切換,只能靠點擊底部的Button來實現。
首先是底部的1個布局文件bottom.xml
<?xml version="1.0" encoding="utf⑻"?>
<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>
簡單的線性布局,放置我們的按鈕。
這個布局在后面的栗子中也會使用。
接下來是1個頂部的title
<?xml version="1.0" encoding="utf⑻"?>
<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>
就1個TextView。
為了簡單起見,這里面的布局只放置1個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要加載的4個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基礎知識,需要各位小火伴爛熟于心。
在上1個栗子當中,我們使用的是FragmentLayout來作為填充Fragment的容器。當使用ViewPage,我們需要把布局文件中的Layout替換成ViewPager。這就要求開發者對ViewPager的使用有基本的了解。
可以看到使用了ViewPager以后不但可以實現左右的滑動,而且還能通過底部的點擊來實現頁面切換的效果
首先是布局文件
<?xml version="1.0" encoding="utf⑻"?>
<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<View> 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裝載進去的,雖然也能夠實現和和采取FragmentPagerAdapter1樣的效果,但是如果這么做,必定所有的邏輯控制都放在MainActivity當中,對后期代碼的保護10分不利。
使用FragmentPagerAdapter的好處之1就是能夠使得當前頁面的邏輯處理唯一當前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<Fragment> 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);
}
}
如果每次在開發的進程當中都去寫1個這樣的Tab頁面,無疑耗時耗力,固然,對初學者而言,這類“耗時耗力”能夠幫助他們了解效果實現的基本實現原理。
在這里推薦給大家1款比較不錯的ViewPager框架:
LuckyJayce/ViewPagerIndicator
里面的介紹比較詳細,這里就不多講了,對這個框架感興趣的小火伴可以去github上仔細研讀1下~
最后附上下載的源碼:github