在Android4.0中Contacts拨号界面分页方式剖析

在Android4.0中,Contacts 拨号界面的分页方式是怎么样的呢?是通过传统的TabHost+tab的方式吗?

不是的,而是通过ActionBar + tab+ view Pager的方式实现的。

具体的实现详情,请见下面的详细剖析。

在DialtactsActivity类中,通过向ActionBar中添加Tab的方式实现分页,每页显示的内容,则通过ViewPager对象设置的Adapter对象来设置。

在onCreate()方法中

顺序调用

setupDialer();

setupCallLog();

setupFavorites();

方法加载将三哥tab加载到ActionBar中

下面以setupDialer为例,逐行描述一下其加载过程

private void setupDialer(){

       final Tab tab = getActionBar().newTab();

       tab.setContentDescription(R.string.dialerIconLabel);

       tab.setTabListener(mTabListener);      

       tab.setIcon(R.drawable.ic_tab_dialer);

       getActionBar().addTab(tab);

 }

final Tab tab =getActionBar().newTab();

新建一个Tab页

tab.setContentDescription(R.string.dialerIconLabel);

为该tab也设置描述,基本上没意义,也不显示,只是存储一些临时的数据

tab.setTabListener(mTabListener);

设置监听器,当点击该tab页时触发该事件

tab.setIcon(R.drawable.ic_tab_dialer);

给该tab也添加显示的图标

getActionBar().addTab(tab);

将该tab页添加到ActionBar中

其它几个方法的具体实现也类似。

那么,您想想, Activity多次调用getActionBar().addTab(tab) 添加tab都是添加到一个ActionBar中了吗?有此疑问的朋友请点击 

那么创建三个tab就可以了吗?

不是的,DialtactsActivity中又对ActionBar进行了下面的处理

getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

getActionBar().setDisplayShowTitleEnabled(false);

getActionBar().setDisplayShowHomeEnabled(false);

第一句将ActionBar设置为“Tab导航”模式

第二句将ActionBar设置为标题不可见

第三句将ActionBar设置为显示主界面按钮不可用

 

是不是感觉缺了点什么?tab页内显示的内容呢?

先别急,我们继续往下走

上文提到tab.setTabListener(mTabListener),现在我们来看看这个监听器到底做了什么

 

private final TabListenermTabListener = new TabListener() {

  @Override

  public void onTabUnselected(Tab tab, FragmentTransaction ft){

  }

 @Override

  public void onTabSelected(Tab tab, FragmentTransaction ft){

      if (mViewPager.getCurrentItem() != tab.getPosition()) {

            mViewPager.setCurrentItem(tab.getPosition(), true);        

       }

….

   }

 

       @Override

   public void onTabReselected(Tab tab, FragmentTransaction ft){

       }

   };

看到了吗?

  if (mViewPager.getCurrentItem() !=tab.getPosition()) {

            mViewPager.setCurrentItem(tab.getPosition(), true);        

  }

将tab和ViewPager联系到一起了。

tab.getPosition()获得当前tab的位置返回int值

mViewPager.getCurrentItem()返回滑动页当前的item编号,返回int值

mViewPager.setCurrentItem(tab.getPosition(), true);设置viewPager的平滑滚动到tab设置的位置

当tab的位置和ViewPager的当前页不等时,重新设置viewpager的当前页

看样子就是这了,tab页的内容肯定就是通过mViewPager来设置的。

 

下面我们继续跟进mViewPager

private ViewPager mViewPager;

首先声明mViewPager为类的私有成员

在onCreate()方法中被初始化

mViewPager = (ViewPager)findViewById(R.id.pager);

mViewPager.setAdapter(newViewPagerAdapter(getFragmentManager()));

mViewPager.setOnPageChangeListener(mPageChangeListener);

第一句

mViewPager = (ViewPager)findViewById(R.id.pager);

我们来看类的布局文件dialtacts_activity.xml文件

在该文件中有一处

<com.android.contacts.activities.DialtactsViewPager

       android:id="@+id/pager"

       android:layout_width="match_parent"

       android:layout_height="match_parent" />

原来mViewPager就是布局中的pager啊

com.android.contacts.activities.DialtactsViewPager

好像不是传统的ViewPager,难道DialtactsViewPager继承了DialtactsViewPager?

答案是正确的

public classDialtactsViewPager extends ViewPager

 

好,我们接下来继续看看viewPager对象往下都做了些什么

第二句mViewPager.setAdapter(newViewPagerAdapter(getFragmentManager()));

为ViewPager对象设置了一个Adapter

我们来看看Adapter的具体内容

public classViewPagerAdapter extends FragmentPagerAdapter {

       private DialpadFragment mDialpadFragment;

       private CallLogFragment mCallLogFragment;

       private PhoneFavoriteFragment mPhoneFavoriteFragment;

 

       public ViewPagerAdapter(FragmentManager fm) {

           super(fm);

       }

 

       @Override

       public Fragment getItem(int position) {

           switch (position) {

               case TAB_INDEX_DIALER:

                   if (mDialpadFragment == null) {

                        mDialpadFragment= new DialpadFragment();

                   }

                   return mDialpadFragment;

                        …

           }

           throw new IllegalStateException("No fragment at position " +position);

       }

 

       @Override

       public int getCount() {

           return TAB_INDEX_COUNT;

       }

   }

哦,我明白了,原来在Adapter里面建立了三种Fragment对象

然后通过当前的选中位置来返回当前页是哪个fragment对象,在fragment对象里面设置页面的具体内容。

 

既然Adapter设置好了,已经可以滑动了,也就是已经可以实现切换效果了,google接下来还要干什么了呢?

mViewPager.setOnPageChangeListener(mPageChangeListener);

  private classPageChangeListener implementsOnPageChangeListener{

    private int mCurrentPosition = -1;

    private int mNextPosition = -1;

 

    @Override

    public void onPageScrolled(

           int position, float positionOffset, int positionOffsetPixels){

    }

     @Override

     public void onPageSelected(int position) {

        final ActionBar actionBar = getActionBar();

        if (mCurrentPosition == position) {

          Log.w(TAG,"Previous position and next position became same (" + position +")");

        }

        actionBar.selectTab(actionBar.getTabAt(position));

        mNextPosition = position;

     }

     public void setCurrentPosition(int position) {

           mCurrentPosition= position;

     }

     @Override

     public void onPageScrollStateChanged(int state) {

           switch (state) {

               case ViewPager.SCROLL_STATE_IDLE: {

                   if (mCurrentPosition >= 0) {

                       sendFragmentVisibilityChange(mCurrentPosition,false);

                   }

                   if (mNextPosition >= 0) {

                       sendFragmentVisibilityChange(mNextPosition, true);

                   }

                   invalidateOptionsMenu();

 

                   mCurrentPosition = mNextPosition;

                   break;

               }

               case ViewPager.SCROLL_STATE_DRAGGING:

               case ViewPager.SCROLL_STATE_SETTLING:

               default:

                   break;

           }

       }

   }

private FragmentgetFragmentAt(int position) {

       switch (position) {

           case TAB_INDEX_DIALER:

               return mDialpadFragment;

           case TAB_INDEX_CALL_LOG:

               returnmCallLogFragment;

           case TAB_INDEX_FAVORITES:

               return mPhoneFavoriteFragment;

           default:

               throw new IllegalStateException("Unknown fragment index: " +position);

       }

   }

 

   private void sendFragmentVisibilityChange(int position, booleanvisibility) {

       final Fragment fragment = getFragmentAt(position);

       if (fragment instanceof ViewPagerVisibilityListener) {

           ((ViewPagerVisibilityListener)fragment).onVisibilityChanged(visibility);

       }

}

通过上面的操作,了解到PageChangeListener 的主要作用是在页面滑动过程中,menu菜单键有可见到不可见的。


你可能感兴趣的:(android,Google,layout,float,tabs,menu)