Android系统联系人全特效实现(下),字母表快速滚动
在上一篇文章中,我和大家一起实现了类似于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" >
- <ListView
- android: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>
- <LinearLayout
- android:id="@+id/title_layout"
- android:layout_width="fill_parent"
- android:layout_height="18dip"
- android:layout_alignParentTop="true"
- android:background="#303030" >
- <TextView
- android: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() {
- @Override
- public 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;
- @Override
- protected 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() {
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- }
- @Override
- public 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() {
- @Override
- public 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系统联系人全特效实现(下),字母表快速滚动的更多相关文章
- android系统联系人分组特效实现(2)---字母表快速滚动
要实现这种功能,只需要在 android系统联系人分组特效实现(1)---分组导航和挤压动画 的基础上再加上一个自定义控件即可完成. 1.新建项目,继续新建一个java类,BladeView,用 ...
- Android系统联系人全特效实现(上),分组导航和挤压动画
记得在我刚接触Android的时候对系统联系人中的特效很感兴趣,它会根据手机中联系人姓氏的首字母进行分组,并在界面的最顶端始终显示一个当前的分组.如下图所示: 最让我感兴趣的是,当后一个分组和前一个分 ...
- android系统联系人分组特效实现(1)---分组导航和挤压动画
1.打开activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/andr ...
- [置顶] android系统如何在静音模式下关闭camera拍照声音(2)
之前写过一篇“android系统如何在静音模式下关闭camera拍照声音”的博客,今天来写他的续篇,继续探讨这个问题. 公司新需求,要求在camera应用中添加一个开关,可以进行拍照声音的关闭和开启. ...
- Android零基础入门第2节:Android 系统架构和应用组件那些事
原文:Android零基础入门第2节:Android 系统架构和应用组件那些事 继上一期浅谈了Android的前世今生,这一期一起来大致回顾一下Android 系统架构和应用组件. 一.Android ...
- 如何学习Android系统源码(转)
一. Android系统的源代码非常庞大和复杂,我们不能贸然进入,否则很容易在里面迷入方向,进而失去研究它的信心.我们应该在分析它的源代码之前学习好一些理论知识,下面就介绍一些与Android系统相关 ...
- Android入门学习:Android 系统框架及应用程序执行过程
Android基础知识学习 新手上路,还请多多帮助.由于初学,博客内容难免有不正确的地方,还请各位多多指教,相互学习! 主要内容: 1.Android层次架构及主要功能 2.Android编程模型,程 ...
- Android系统权限和root权限大全
tyle="margin:20px 0px 0px; font-size:14.285714149475098px; line-height:26px; font-family:Arial; ...
- Android系统关机或几种方式重启
---------------------------------------------------------------------------------------------------- ...
随机推荐
- smack capable(CAP_MAC_OVERRIDE)
https://blog.csdn.net/ning_wei/article/details/9670947 LINUX中的capable int smk_curacc(char *obj_label ...
- 【Codeforces Round #437 (Div. 2) B】Save the problem!
[链接]h在这里写链接 [题意] 给你一个金额N,和硬币的类型总数M; (完全背包),然后问你组成N的方案数. 使得,用这些硬币组成价值为N的金额的方案数为A; 现在A ...
- YASM User Manual
This document is the user manual for the Yasm assembler. It is intended as both an introduction and ...
- java并发之生产者消费者模型
生产者和消费者模型是操作系统中经典的同步问题.该问题最早由Dijkstra提出,用以演示它提出的信号量机制. 经典的生产者和消费者模型的描写叙述是:有一群生产者进程在生产产品.并将这些产品提供给消费者 ...
- Android之怎样用代码使编辑框等组件显示为圆角
圆角button实现 圆角button大家很常见.有时候你可能会使用ps来加工圆角图片来实现想要的效果, 今天通过简短的代码来达到这样的效果.(由于这个跟project无关.仅仅是一种效果,所以我就单 ...
- POJ 2014 Flow Layout 模拟
http://poj.org/problem?id=2014 嘻嘻2014要到啦,于是去做Prob.ID 为2014的题~~~~祝大家新年快乐~~ 题目大意: 给你一个最大宽度的矩形,要求把小矩形排放 ...
- SpringCloud微服务学习笔记
SpringCloud微服务学习笔记 项目地址: https://github.com/taoweidong/Micro-service-learning 单体架构(Monolithic架构) Mon ...
- js进阶 11-22/23 js如何实现选项卡
js进阶 11-22/23 js如何实现选项卡 一.总结 一句话总结:通过索引把选项卡头的li标签和选项卡内容的div标签联系在一起,通过控制div标签的display属性可以实现选项卡的选项切换. ...
- Struts2与Spring的整合
今天倒腾了半天,终于是把这个两个框架整合到一起了.还是要写一下总结,同时给大家一些帮助. 开发环境:myeclipse 9.0(不好用!)tomcat6.0 1.准备工作 需要导入的包:struts2 ...
- ie7easyui的书写要规范
在书写easyui对象的属性,有时候习惯在,属性的末尾再加一个“,”,这个在高版本浏览器是没事的,但是在ie7及以下,会有报错