- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Android系统联系人全特效实现(上)分组导航和挤压动画(附源码)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
记得在我刚接触android的时候对系统联系人中的特效很感兴趣,它会根据手机中联系人姓氏的首字母进行分组,并在界面的最顶端始终显示一个当前的分组。如下图所示: 最让我感兴趣的是,当后一个分组和前一个分组相碰时,会产生一个上顶的挤压动画。那个时候我思考了各种方法想去实现这种特效,可是限于功夫不到家,都未能成功。如今两年多过去了,自己也成长了很多,再回头去想想这个功能,突然发现已经有了思路,于是立刻记录下来与大家分享。 首先讲一下需要提前了解的知识点,这里我们最需要用到的就是sectionindexer,它能够有效地帮助我们对分组进行控制。由于sectionindexer是一个接口,你可以自定义一个子类来实现sectionindexer,不过自己再写一个sectionindexer的实现太麻烦了,这里我们直接使用android提供好的实现alphabetindexer,用它来实现联系人分组功能已经足够了。 alphabetindexer的构造函数需要传入三个参数,第一个参数是cursor,第二个参数是sortedcolumnindex整型,第三个参数是alphabet字符串。其中cursor就是把我们从数据库中查出的游标传进去,sortedcolumnindex就是指明我们是使用哪一列进行排序的,而alphabet则是指定字母表排序规则,比如:"abcdefghijklmnopqrstuvwxyz"。有了alphabetindexer,我们就可以通过它的getpositionforsection和getsectionforposition方法,找出当前位置所在的分组,和当前分组所在的位置,从而实现类似于系统联系人的分组导航和挤压动画效果,关于alphabetindexer更详细的详解,请参考官方文档。 那么我们应该怎样对联系人进行排序呢?前面也提到过,有一个sortedcolumnindex参数,这个sortedcolumn到底在哪里呢?我们来看一下系统联系人的raw_contacts这张表(/data/data/com.android.providers.contacts/databases/contacts2.db),这个表结构比较复杂,里面有二十多个列,其中有一列名叫sort_key,这就是我们要找的了!如下图所示: 可以看到,这一列非常人性化地帮我们记录了汉字所对应的拼音,这样我们就可以通过这一列的值轻松为联系人进行排序了。 下面我们就来开始实现,新建一个android项目,命名为contactsdemo。首先我们还是先来完成布局文件,打开或新建activity_main.xml作为程序的主布局文件,在里面加入如下代码:
复制代码 代码如下
<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: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> </relativelayout> 。
布局文件很简单,里面放入了一个listview,用于展示联系人信息。另外还在头部放了一个linearlayout,里面包含了一个textview,它的作用是在界面头部始终显示一个当前分组。 然后新建一个contact_item.xml的布局,这个布局用于在listview中的每一行进行填充,代码如下:
复制代码 代码如下
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <linearlayout android:id="@+id/sort_key_layout" android:layout_width="fill_parent" android:layout_height="18dip" android:background="#303030" > <textview android:id="@+id/sort_key" 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> <linearlayout android:id="@+id/name_layout" android:layout_width="fill_parent" android:layout_height="50dip" > <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginleft="10dip" android:layout_marginright="10dip" android:src="@drawable/icon" /> <textview android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textcolor="#ffffff" android:textsize="22sp" /> </linearlayout> </linearlayout> 。
在这个布局文件中,首先是放入了一个和前面完成一样的分组布局,因为不仅界面头部需要展示分组,在每个分组内的第一个无素之前都需要展示分组布局。然后是加入一个简单的linearlayout,里面包含了一个imageview用于显示联系人头像,还包含一个textview用于显示联系人姓名。 这样我们的布局文件就全部写完了,下面开始来真正地实现功能。 先从简单的开始,新建一个contact实体类
复制代码 代码如下
public class contact { /** * 联系人姓名 */ private string name; /** * 排序字母 */ private string sortkey; public string getname() { return name; } public void setname(string name) { this.name = name; } public string getsortkey() { return sortkey; } public void setsortkey(string sortkey) { this.sortkey = sortkey; } } 。
这个实体类很简单,只包含了联系人姓名和排序键。 接下来完成联系人列表适配器的编写,新建一个contactadapter类继承自arrayadapter,加入如下代码:
复制代码 代码如下
public class contactadapter extends arrayadapter<contact> { /** * 需要渲染的item布局文件 */ private int resource; /** * 字母表分组工具 */ private sectionindexer mindexer; public contactadapter(context context, int textviewresourceid, list<contact> objects) { super(context, textviewresourceid, objects); resource = textviewresourceid; } @override public view getview(int position, view convertview, viewgroup parent) { contact contact = getitem(position); linearlayout layout = null; if (convertview == null) { layout = (linearlayout) layoutinflater.from(getcontext()).inflate(resource, null); } else { layout = (linearlayout) convertview; } textview name = (textview) layout.findviewbyid(r.id.name); linearlayout sortkeylayout = (linearlayout) layout.findviewbyid(r.id.sort_key_layout); textview sortkey = (textview) layout.findviewbyid(r.id.sort_key); name.settext(contact.getname()); int section = mindexer.getsectionforposition(position); if (position == mindexer.getpositionforsection(section)) { sortkey.settext(contact.getsortkey()); sortkeylayout.setvisibility(view.visible); } else { sortkeylayout.setvisibility(view.gone); } return layout; } /** * 给当前适配器传入一个分组工具。 * * @param indexer */ public void setindexer(sectionindexer indexer) { mindexer = indexer; } } 。
上面的代码中,最重要的就是getview方法,在这个方法中,我们使用sectionindexer的getsectionforposition方法,通过当前的position值拿到了对应的section值,然后再反向通过刚刚拿到的section值,调用getpositionforsection方法,取回新的position值。如果当前的position值和新的position值是相等的,那么我们就可以认为当前position的项是某个分组下的第一个元素,我们应该将分组布局显示出来,而其它的情况就应该将分组布局隐藏。 最后我们来编写程序的主界面,打开或新建mainactivity作为程序的主界面,代码如下所示:
复制代码 代码如下
public class mainactivity extends activity { /** * 分组的布局 */ private linearlayout titlelayout; /** * 分组上显示的字母 */ private textview title; /** * 联系人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); title = (textview) findviewbyid(r.id.title); 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(); } } /** * 为联系人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; } }); } /** * 获取sort key的首个字符,如果是英文字母就直接返回,否则返回#。 * * @param sortkeystring * 数据库中读取出的sort key * @return 英文字母或者# */ private string getsortkey(string sortkeystring) { string key = sortkeystring.substring(0, 1).touppercase(); if (key.matches("[a-z]")) { return key; } return "#"; } } 。
可以看到,在oncreate方法中,我们从系统联系人数据库中去查询联系人的姓名和排序键,之后将查询返回的cursor直接传入alphabetindexer作为第一个参数。由于我们一共就查了两列,排序键在第二列,所以我们第二个sortedcolumnindex参数传入1。第三个alphabet参数这里传入了"#abcdefghijklmnopqrstuvwxyz"字符串,因为可能有些联系人的姓名不在字母表范围内,我们统一用#来表示这部分联系人。 然后我们在setupcontactslistview方法中监听了listview的滚动,在onscroll方法中通过getsectionforposition方法获取第一个可见元素的分组值,然后给该分组值加1,再通过getpositionforsection方法或者到下一个分组中的第一个元素,如果下个分组的第一个元素值等于第一个可见元素的值加1,那就说明下个分组的布局要和界面顶部分组布局相碰了。之后再通过listview的getchildat(0)方法,获取到界面上显示的第一个子view,再用view.getbottom获取底部距离父窗口的位置,对比分组布局的高度来对顶部分组布局进行纵向偏移,就可以实现挤压动画的效果了。 最后给出androidmanifest.xml的代码,由于要读取手机联系人,因此需要加上android.permission.read_contacts的声明:
复制代码 代码如下
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.contactsdemo" android:versioncode="1" android:versionname="1.0" > <uses-sdk android:minsdkversion="8" android:targetsdkversion="8" /> <uses-permission android:name="android.permission.read_contacts"></uses-permission> <application android:allowbackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@android:style/theme.notitlebar" > <activity android:name="com.example.contactsdemo.mainactivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> </application> </manifest> 。
现在我们来运行一下程序,效果如下图所示: 目前的话,分组导航和挤压动画效果都已经完成了,看起来感觉还是挺不错的,下一篇文章我会带领大家继续完善这个程序,加入字母表快速滚动功能。 好了,今天的讲解到此结束,有疑问的朋友请在下面留言。 源码下载,请点击这里 。
最后此篇关于Android系统联系人全特效实现(上)分组导航和挤压动画(附源码)的文章就讲到这里了,如果你想了解更多关于Android系统联系人全特效实现(上)分组导航和挤压动画(附源码)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
ion-nav-view 嵌套有一个奇怪的问题。当我在浏览器中加载应用程序时,我可以看到 URL 正在更改为 /app/menu,但页面上没有出现 menu.html 中的内容。页面是空白的。 以下是
运行截图如下: 源码如下: CN_TEST1
我正在开发一个示例reactjs应用程序(在学习过程中)。我有一个页面,其中列出了用户列表和一个用于添加新用户的添加按钮。 当我单击添加按钮时,我应该导航到用户表单以创建新用户。 单击用户表单中的提交
我的导航栏中的导航链接有问题。首先,它没有在导航栏中间对齐,如下所示: 另一部分是,我正在使用填充来执行此操作,因此如果我放置除“测试”以外的任何内容或将其放在不同的情况下,等等。它会重复该框。代码预
基本上,我有一个网站,我正在尝试使用 ajax 导航构建它,以便它获取网页并将它们加载到同一页面中。问题是当我正常放入内容时它工作正常但是当我尝试将内容添加到外部文档并从导航中访问它时框拆分你可以在这
以下站点左侧菜单的导航使用 CSS 进行鼠标悬停链接。 PVH 当我获取导航代码并将其设为单独的页面时。然后鼠标悬停链接不起作用。可能是什么原因? Test 最佳答案 可能... 对此事有话要说
一 问题描述 标准的 Web 浏览器包含在最近访问过的页面中向后和向前移动的功能。实现这些特性的一种方法是使用双栈来跟踪前后移动可以到达的页面。 Web 导航支持下面的命令。 后退页面:将当前页面推到
我想有条件地导航到某个页面。如果某些条件为真,我想导航到其他页面,否则我想留在同一页面上。我有类似的东西:- 在 bean.navigate 我有类似的东西:- public String navi
问题:有没有办法让按钮在用户控件中表现得像超链接? 我已经搜索了几天,但没有找到解决此问题的人。如何使用按钮在 WPF 应用程序中导航?具体来说,如何使用户控件内的按钮在其主机框架中导航?请记住,用户
我尝试使用 Android Navigation 组件并遇到了回栈问题。 我有 fragment A,B。 我写的: Navigation.findNavController(view).naviga
我有一个父布局,并从该子站点派生而来。 父级布局具有一个导航,每个导航点代表一个子站点。 如何在父布局中突出显示当前查看的子站点? 如果看起来如何? 最佳答案 可能不是最好的选择,但这是基于路由名称的
我正在开发Blazor服务器端应用程序。熟悉Blazor的任何人都在左侧的NavBar中填充超链接,并以特殊的CSS类进行装饰。我的问题是,如果任何内容都已编辑,我将试图停止导航并在一个特定页面上显示
我是 flutter 的新手,我正在开发一个具有多个屏幕的应用程序。 我想知道如何阻止 flutter 创建同一路线的多个屏幕, 例如我有 第1页和 第2页 ,如果我单击按钮导航到第 2 页并再次单击
我们的设计师创建了一个类似于上面屏幕的布局。主要思想是创建一个只有一个屏幕的应用程序,当您点击一个按钮时,屏幕的红色部分会发生变化(即 2 个文本框而不是 1 个文本框)。这个应用程序将是一个多平台应
有人可以解释为什么从pageE返回时不打印efeioi吗? 页面A Navigator.pushNamed(context, PageB.ROUTE).then((onValue) {
我需要在 iOS 应用程序中创建一个导航,如下图所示。 它包含一个标签栏和一个侧边菜单。 问题是正确的导航菜单按钮,应该在所有选项卡中都可见。甚至每个选项卡的所有内部屏幕。 当用户从侧面菜单中选择一个
这个问题在这里已经有了答案: Vim: move around quickly inside of long line (8 个答案) 关闭 8 年前。 我正在用 vim 编辑一个文本文件,我已经使
我很困惑,如何执行操作来创建从用户位置到用户选择/点击图钉覆盖层的图钉覆盖层(谷歌位置)的路线/导航。这是我的 map Activity ,它将显示我的 map 。 public class Plac
我正在使用 jQuery 函数 .animate 来一一突出显示导航链接。他们在 ul 中。我可以让它工作,只是想知道是否有一种方法可以缩短我的代码,这样我就不必单独突出显示每个项目。提前致谢 $(d
我正在创建一个带有“ anchor 导航”的网站,就像 Facebook 和谷歌邮件一样。我已经让它工作了,但还不完全。当我加载带有 #contact 之类的页面时,除非我单击它的链接,否则它不会加载
我是一名优秀的程序员,十分优秀!