`

Android4.0中Contacts拨号界面分页方式剖析(源码)

 
阅读更多
转自:http://blog.sina.com.cn/s/blog_9f233c070101azf1.html

在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 TabListener mTabListener = 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(new ViewPagerAdapter(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 class DialtactsViewPager extends ViewPager



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

第二句mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));

为ViewPager对象设置了一个Adapter

我们来看看Adapter的具体内容

public class ViewPagerAdapter 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 class PageChangeListener implements OnPageChangeListener {

     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 Fragment getFragmentAt(int position) {

        switch (position) {

            case TAB_INDEX_DIALER:

                return mDialpadFragment;

            case TAB_INDEX_CALL_LOG:

                return mCallLogFragment;

            case TAB_INDEX_FAVORITES:

                return mPhoneFavoriteFragment;

            default:

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

        }

    }



    private void sendFragmentVisibilityChange(int position, boolean visibility) {

        final Fragment fragment = getFragmentAt(position);

        if (fragment instanceof ViewPagerVisibilityListener) {

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

        }

}

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

最后希望朋友们按照我的思路自己跟一遍代码,这样您将会得到更大的收获,小弟才疏学浅,有肯定地方不到位,希望大家指正!

如果我的一点点总结,对您的有一丁点帮助,那么我将会感到莫大的欣慰!
分享到:
评论

相关推荐

    android系统模块之Contacts的学习笔记

    现在转向Android 4.0(Ice Cream Sandwich)中的Contacts拨号界面。在这个版本中,开发者使用了一种不同于传统TabHost的分页方式,即结合ActionBar、Tab和ViewPager实现页面切换。这种方式提供了更现代和流畅的用户...

    android4.1 联系人模块源码 Contacts.rar

    在Android 4.1(JellyBean)系统中,联系人模块是用户界面与系统通讯录数据交互的核心部分。此源码压缩包“Contacts.rar”提供了深入理解Android联系人应用内部工作原理的机会,有助于开发者更好地定制和扩展联系人...

    android 完整的拨号应用源码.rar

    【Android 完整拨号应用源码解析】 ...通过分析这份源码,开发者不仅可以学习到如何构建一个完整的拨号应用,还能了解到Android系统的核心组件是如何协同工作的,这将对提升Android开发技能大有裨益。

    Android2.1系统通讯录源码

    在Android操作系统中,通讯录(Contacts)是用户管理和存储联系人信息的核心组件。Android 2.1(Eclair)版本的通讯录源码提供了一个深入理解Android系统如何处理联系人数据、显示联系人列表以及与用户交互的基础。...

    Android程序研发源码Android 私密通讯录源码.zip

    在Android中,常见的数据存储方式有SQLite数据库、SharedPreferences、文件存储和ContentProvider等。源码可能会使用SQLite数据库来存储联系人姓名、电话号码、电子邮件等信息,因为这种方式支持结构化数据,并且...

    Android 手机通讯录实现源码

    首先,Android中的通讯录功能主要依赖于`ContactsContract`类,它是Android SDK提供的一个内容提供者(Content Provider),用于访问和管理手机上的联系人信息。通过这个接口,开发者可以查询、插入、更新或删除联系...

    Android程序研发源码Android 联系人快速索引源码.zip

    通过对这些源码的分析和学习,开发者可以了解如何在自己的Android应用中实现高效、流畅的联系人快速索引功能,提升用户体验。同时,这也是一次深入理解Android数据存储、UI设计和性能优化的好机会。

    Android应用源码之仿腾讯通讯录管理.zip

    在Android中,这通常通过SQLite数据库来实现,开发者需要了解如何创建数据库、表结构,以及如何执行CRUD(创建、读取、更新、删除)操作。此外,ContentProvider也是一个关键组件,它使得不同应用间可以安全地共享...

    手机通讯录源码

    4. 异步处理:为了保持用户界面的流畅性,源码可能采用异步编程模型,比如Android的AsyncTask或iOS的GCD(Grand Central Dispatch),来处理耗时的数据库操作和网络请求。 5. 权限管理:根据最新的隐私政策,访问...

    应用源码获取手机通讯录的实战应用(含SIM卡中的联系人.zip

    源码的学习是提升编程技能的重要途径,通过分析和实践这份代码,你可以深入理解Android的联系人管理和权限机制。 首先,我们要明确Android系统对读取通讯录的权限管理。从Android 6.0(API级别23)开始,应用需要在...

    火星通讯录

    2. **源码分析**:标签中的“源码”暗示我们可能能够深入研究应用的工作原理。源码分析可以帮助开发者学习新的编程技巧,理解应用的架构,以及如何处理常见的Android编程问题,如权限管理、UI设计、数据存储等。 3....

    网站前端网页源码模板 (977).zip

    网站前端网页源码模板(977).zip包含了一系列用于构建网页的基本元素,这些元素是任何网站设计的基础。这个压缩包提供了五个HTML文件,每个文件对应网站的不同部分,以及一些必要的资源文件,如图片、CSS样式表和...

    PHP实例开发源码—EXT+ PHP班级通讯录.zip

    例如,这些框架可能提供了ORM(对象关系映射)工具,如Doctrine,可以让我们用面向对象的方式来操作数据库,而无需直接写SQL。 此外,文件`132687278989557791`可能是该项目的主入口文件,或者包含了项目配置、路由...

Global site tag (gtag.js) - Google Analytics