转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9050671

在上一篇文章中,我和大家一起实现了类似于Android系统联系人的分组导航和挤压动画功能,不过既然文章名叫做《Android系统联系人全特效实现》,那么没有快速滚动功能显然是称不上"全"的。因此本篇文章我将带领大家在上篇文章的代码基础上改进,加入快速滚动功能。

如果还没有看过我上一篇文章,请抓紧去阅读一下Android系统联系人全特效实现(上),分组导航和挤压动画。

其实ListView本身是有一个快速滚动属性的,可以通过在XML中设置android:fastScrollEnabled="true"来启用。包括以前老版本的Android联系人中都是使用这种方式来进行快速滚动的。效果如下图所示:

不过这种快速滚动方式比较丑陋,到后来很多手机厂商在定制自己ROM的时候都将默认快速滚动改成了类似iPhone上A-Z字母表快速滚动的方式。这里我们怎么能落后于时代的潮流呢!我们的快速滚动也要使用A-Z字母表的方式!

下面就来开始实现,首先打开上次的ContactsDemo工程,修改activity_main.xml布局文件。由于我们要在界面上加入字母表,因此我们需要一个Button,将这个Button的背景设为一张A-Z排序的图片,然后居右对齐。另外还需要一个TextView,用于在弹出式分组布局上显示当前的分组,默认是gone掉的,只有手指在字母表上滑动时才让它显示出来。修改后的布局文件代码如下:

<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"android:orientation="vertical" ><ListViewandroid:id="@+id/contacts_list_view"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:scrollbars="none"android:fadingEdge="none" ></ListView><LinearLayoutandroid:id="@+id/title_layout"android:layout_width="fill_parent"android:layout_height="18dip"android:layout_alignParentTop="true"android:background="#303030" ><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginLeft="10dip"android:textColor="#ffffff"android:textSize="13sp" /></LinearLayout><Button android:id="@+id/alphabetButton"android:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_alignParentRight="true"android:background="@drawable/a_z"/><RelativeLayout android:id="@+id/section_toast_layout"android:layout_width="70dip"android:layout_height="70dip"android:layout_centerInParent="true"android:background="@drawable/section_toast"android:visibility="gone"><TextView android:id="@+id/section_toast_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:textColor="#fff"android:textSize="30sp"/></RelativeLayout></RelativeLayout>

然后打开MainActivity进行修改,毫无疑问,我们需要对字母表按钮的touch事件进行监听,于是在MainActivity中新增如下代码:

private void setAlpabetListener() {alphabetButton.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {float alphabetHeight = alphabetButton.getHeight();float y = event.getY();int sectionPosition = (int) ((y / alphabetHeight) / (1f / 27f));if (sectionPosition < 0) {sectionPosition = 0;} else if (sectionPosition > 26) {sectionPosition = 26;}String sectionLetter = String.valueOf(alphabet.charAt(sectionPosition));int position = indexer.getPositionForSection(sectionPosition);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:alphabetButton.setBackgroundResource(R.drawable.a_z_click);sectionToastLayout.setVisibility(View.VISIBLE);sectionToastText.setText(sectionLetter);contactsListView.setSelection(position);break;case MotionEvent.ACTION_MOVE:sectionToastText.setText(sectionLetter);contactsListView.setSelection(position);break;default:alphabetButton.setBackgroundResource(R.drawable.a_z);sectionToastLayout.setVisibility(View.GONE);}return true;}});
}

可以看到,在这个方法中我们注册了字母表按钮的onTouch事件,然后在onTouch方法里做了一些逻辑判断和处理,下面我来一一详细说明。首先通过字母表按钮的getHeight方法获取到字母表的总高度,然后用event.getY方法获取到目前手指在字母表上的纵坐标,用纵坐标除以总高度就可以得到一个用小数表示的当前手指所在位置(0表在#端,1表示在Z端)。由于我们的字母表中一共有27个字符,再用刚刚算出的小数再除以1/27就可以得到一个0到27范围内的浮点数,之后再把这个浮点数向下取整,就可以算出我们当前按在哪个字母上了。然后再对event的action进行判断,如果是ACTION_DOWN或ACTION_MOVE,就在弹出式分组上显示当前手指所按的字母,并调用ListView的setSelection方法把列表滚动到相应的分组。如果是其它的action,就将弹出式分组布局隐藏。
MainActivity的完整代码如下:

public class MainActivity extends Activity {/*** 分组的布局*/private LinearLayout titleLayout;/*** 弹出式分组的布局*/private RelativeLayout sectionToastLayout;/*** 右侧可滑动字母表*/private Button alphabetButton;/*** 分组上显示的字母*/private TextView title;/*** 弹出式分组上的文字*/private TextView sectionToastText;/*** 联系人ListView*/private ListView contactsListView;/*** 联系人列表适配器*/private ContactAdapter adapter;/*** 用于进行字母表分组*/private AlphabetIndexer indexer;/*** 存储所有手机中的联系人*/private List<Contact> contacts = new ArrayList<Contact>();/*** 定义字母表的排序规则*/private String alphabet = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";/*** 上次第一个可见元素,用于滚动时记录标识。*/private int lastFirstVisibleItem = -1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);adapter = new ContactAdapter(this, R.layout.contact_item, contacts);titleLayout = (LinearLayout) findViewById(R.id.title_layout);sectionToastLayout = (RelativeLayout) findViewById(R.id.section_toast_layout);title = (TextView) findViewById(R.id.title);sectionToastText = (TextView) findViewById(R.id.section_toast_text);alphabetButton = (Button) findViewById(R.id.alphabetButton);contactsListView = (ListView) findViewById(R.id.contacts_list_view);Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;Cursor cursor = getContentResolver().query(uri,new String[] { "display_name", "sort_key" }, null, null, "sort_key");if (cursor.moveToFirst()) {do {String name = cursor.getString(0);String sortKey = getSortKey(cursor.getString(1));Contact contact = new Contact();contact.setName(name);contact.setSortKey(sortKey);contacts.add(contact);} while (cursor.moveToNext());}startManagingCursor(cursor);indexer = new AlphabetIndexer(cursor, 1, alphabet);adapter.setIndexer(indexer);if (contacts.size() > 0) {setupContactsListView();setAlpabetListener();}}/*** 为联系人ListView设置监听事件,根据当前的滑动状态来改变分组的显示位置,从而实现挤压动画的效果。*/private void setupContactsListView() {contactsListView.setAdapter(adapter);contactsListView.setOnScrollListener(new OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,int totalItemCount) {int section = indexer.getSectionForPosition(firstVisibleItem);int nextSecPosition = indexer.getPositionForSection(section + 1);if (firstVisibleItem != lastFirstVisibleItem) {MarginLayoutParams params = (MarginLayoutParams) titleLayout.getLayoutParams();params.topMargin = 0;titleLayout.setLayoutParams(params);title.setText(String.valueOf(alphabet.charAt(section)));}if (nextSecPosition == firstVisibleItem + 1) {View childView = view.getChildAt(0);if (childView != null) {int titleHeight = titleLayout.getHeight();int bottom = childView.getBottom();MarginLayoutParams params = (MarginLayoutParams) titleLayout.getLayoutParams();if (bottom < titleHeight) {float pushedDistance = bottom - titleHeight;params.topMargin = (int) pushedDistance;titleLayout.setLayoutParams(params);} else {if (params.topMargin != 0) {params.topMargin = 0;titleLayout.setLayoutParams(params);}}}}lastFirstVisibleItem = firstVisibleItem;}});}/*** 设置字母表上的触摸事件,根据当前触摸的位置结合字母表的高度,计算出当前触摸在哪个字母上。* 当手指按在字母表上时,展示弹出式分组。手指离开字母表时,将弹出式分组隐藏。*/private void setAlpabetListener() {alphabetButton.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {float alphabetHeight = alphabetButton.getHeight();float y = event.getY();int sectionPosition = (int) ((y / alphabetHeight) / (1f / 27f));if (sectionPosition < 0) {sectionPosition = 0;} else if (sectionPosition > 26) {sectionPosition = 26;}String sectionLetter = String.valueOf(alphabet.charAt(sectionPosition));int position = indexer.getPositionForSection(sectionPosition);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:alphabetButton.setBackgroundResource(R.drawable.a_z_click);sectionToastLayout.setVisibility(View.VISIBLE);sectionToastText.setText(sectionLetter);contactsListView.setSelection(position);break;case MotionEvent.ACTION_MOVE:sectionToastText.setText(sectionLetter);contactsListView.setSelection(position);break;default:alphabetButton.setBackgroundResource(R.drawable.a_z);sectionToastLayout.setVisibility(View.GONE);}return true;}});}/*** 获取sort key的首个字符,如果是英文字母就直接返回,否则返回#。* * @param sortKeyString*            数据库中读取出的sort key* @return 英文字母或者#*/private String getSortKey(String sortKeyString) {alphabetButton.getHeight();String key = sortKeyString.substring(0, 1).toUpperCase();if (key.matches("[A-Z]")) {return key;}return "#";}}

好了,就改动了以上两处,其它文件都保持不变,让我们来运行一下看看效果:

非常不错!当你的手指在右侧字母表上滑动时,联系人的列表也跟着相应的变动,并在屏幕中央显示一个当前的分组。

现在让我们回数一下,分组导航、挤压动画、字母表快速滚动,Android系统联系人全特效都实现了!

好了,今天的讲解到此结束,有疑问的朋友请在下面留言。

源码下载,请点击这里

Android系统联系人全特效实现(下),字母表快速滚动相关推荐

  1. Android系统联系人全特效实现(上),分组导航和挤压动画

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9033553 记得在我刚接触Android的时候对系统联系人中的特效很感兴趣,它会根 ...

  2. android流程点击开机键熄屏,一种基于android系统的灭屏状态下指纹解锁加速亮屏方法与流程...

    本发明涉及android系统解锁显示方法,尤其涉及一种基于android系统的灭屏状态下指纹解锁加速亮屏方法. 背景技术: 目前,随着指纹技术越来越普及,很多android系统设备都带有指纹外设,特别 ...

  3. android系统如何在静音模式下关闭camera拍照声音

    话说为了防止偷拍,业内有不成文规定,手机公司在做camera时,点击拍照和录像键的时候,必须要有提示音.因此,google也就非常人性化的将播放拍照声音的函数,放到了cameraService中,防止 ...

  4. android系统如何在静音模式下关闭camera拍照声音(2)

    之前写过一篇"android系统如何在静音模式下关闭camera拍照声音"的博客,今天来写他的续篇,继续探讨这个问题. 公司新需求,要求在camera应用中添加一个开关,可以进行拍 ...

  5. android系统源码的环境下用make来编译,Android源码编译系统入门

    做过 Android 平台开发的朋友对make,mm或make clean命令应该很熟悉,但也许大家只是熟知这些命令的作用却不知道这些命令底下有些什么原理?那么今天我就带着大家推开Android编译系 ...

  6. 高德地图:解决android系统在锁屏条件下无法持续定位

    目录 一.简介 二.实现步骤 2.1创建AIDL文件 2.2回调接口 2.3定位服务实现 一.简介 之前公司在app中以android5.0为适用版本添加了轨迹功能用于记录用户健走路线.由于现在用户手 ...

  7. Android系统framework的base目录下编译生成对应oat和art

    比如frameworks\base\core\java\android\hardware\Camera.java,对应system\framework\framework.jar,怎么知道是对应fra ...

  8. android 特效相机实现,基于Android系统的相机特效软件的设计与实现

    摘要: 最近几年,随着科学技术的高速发展,智能手机或者智能平板等一些移动智能设备在各个年龄段的人群中已经有了非常高的普及率.这些智能设备与现代通信技术的紧密结合实现了音乐.图像.视频等多媒体信息与互联 ...

  9. android系统联系人可以转到blackberry os 7.,采取2步验证后如何同步iCloud联系人到黑莓OS10手机...

    我的备用机黑莓Q10之前一直使用iCloud同步联系人,直到约1个多月前,这个功能突然失效了,经常收到系统的通知,具体内容忘了,总之是不能再继续顺利进行联系人同步.虽然发生这个问题之后我几乎立刻就意识 ...

最新文章

  1. 20160115广州MVP线下聚会
  2. 革命性存储:易安ESATA系列产品详解
  3. Java编程思想 第十章:内部类
  4. .NET开发Windows Service程序 - Topshelf
  5. 使用VM Tools让VMware虚拟机里的ubuntu能够共享Windows系统的文件夹
  6. numpy练习100道题
  7. spark 安装配置
  8. BSD配置SSH服务
  9. Vue笔记-Ant Design Vue构建前端连接后端WebSocket
  10. 使用代理,调用json-server的服务接口
  11. Supervisor 配置文件
  12. 力扣每日一刷 -两个数组的交集II
  13. vb杨辉三角代码编写_VB语言中输出杨辉三角形的方法
  14. 大项目售前、售中和售后感悟
  15. python-漫天星星turtle and random
  16. 网站架构资料收集整理
  17. 三角形网格的TBN矩阵中的Tangent计算。
  18. 芯动科技2023校招 FPGA岗位笔试
  19. COM---EXE中的服务器
  20. 关于 iOS 游戏发展趋势的思考

热门文章

  1. WCF分布式开发常见错误(3):客户端调用服务出错
  2. vc 环境下mysql_windows-VC++6.0环境下C++链接MySQL数据库
  3. php 匹配非数字,正则表达式 - 获取匹配和非获取匹配
  4. linux文件元数据,linux编程stat检测文件元数据信息
  5. weblogic修改banner_Via WLST Monitor Weblogic Server
  6. java国际化 英语的标识符_(转)Java 国际化
  7. 组件中使用_尚德高效组件全线投入壳牌首个光伏项目中使用
  8. Linux下查看某个进程占用的CPU及内存
  9. python21天打卡Day6-元组
  10. mysql 把主键当外键_MySQL主键和外键使用及说明