1适配器实现SectionIndexer接口
@Override public Object[] getSections() { return new Object[0]; } //此方法是通过字母的Ascii码,与集合里的元素拼音的首字母的Ascii码做比较,返回第一个相同的索引位置(即分组位置) @Override public int getPositionForSection(int sectionIndex) { for (int i = 0; i < friends.size(); i++) { if (sectionIndex == friends.get(i).pinyin.toUpperCase().charAt(0)) { return i; } } return 0; } //此方法是通过索引位置,获取到此索引所属的分组字母 @Override public int getSectionForPosition(int position) { return friends.get(position).pinyin.toUpperCase().charAt(0); }
2在XML文件里放置一个伪item,遮挡住listview的第一个item,它用来做碰撞位移
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
>
<ListView
android:id="@+id/listview_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
<LinearLayout
android:id="@+id/title_layout"
android:layout_width="fill_parent"
android:layout_height="30dp"
android:layout_gravity="right|top"
android:background="#ff303030"
android:orientation="vertical" >
<TextView
android:id="@+id/title_layout_catalog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="22sp"
android:textColor="@android:color/white"
android:background="@android:color/holo_green_light"
android:gravity="center"
/>
</LinearLayout>
<com.explam.slidelayoutdemo.QuickIndexBar
android:id="@+id/quick_index"
android:background="#f00"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"/>
<TextView
android:id="@+id/tv_letter"
android:visibility="invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/quick_index"
/>
</RelativeLayout>
3在代码里设置listview的滚动监听,通过firstVisibleItem去判断所属分类,当(firstVisibleItem + 1 == nextSectionPosition)第一个可见条目的下一个item与判断出来的下一个分类的位置相同的时候,就要开始进行碰撞效果实现
//设置滚动监听,去实现挤压效果 mLv_main.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //通过第一个可见条目索引拿到这个位置的Ascii码,即字母A的Ascii码 int section = adapter.getSectionForPosition(firstVisibleItem); //获取第二个可见条目位置的Ascii码,可能是A,也可能是其他 int nextSection = adapter.getSectionForPosition(firstVisibleItem + 1); //通过第二个可见条目的Ascci码,拿到它的字母的位置 int nextSectionPosition = adapter.getPositionForSection(nextSection); System.out.println("next:"+(+nextSection)); float titleY = view.getY();//获取listview在容器里的Y坐标(其实就是0) //如果上次记录的可见条目索引不等于现在的滚动到的可见条目索引 if (lastVisibleIndex != firstVisibleItem) { //就将固定在顶部的伪item布局的文本设置为当前可见条目的分类名 mTitle.setText((char) section + ""); } //如果当前可见条目的下一个条目就是下一个分组字母的位置 if (firstVisibleItem + 1 == nextSectionPosition) { View firstView = view.getChildAt(0);//获取listview当前显示的第一个孩子 int bottom = firstView.getBottom();//得到第一个孩子当前的底部bottom int titleLayoutHeight = titleLayout.getHeight(); //如果bottom小于伪item的容器高度,说明要开始进行挤压碰撞了 if (bottom < titleLayoutHeight) { //求出差值,即需要设置给伪容器的y坐标,实现碰撞效果 titleY = bottom - titleLayoutHeight; } } //未满足上面的条件,就将伪容器的y坐标设置的和listview一样,满足了就设置计算的值 titleLayout.setY(titleY); lastVisibleIndex = firstVisibleItem; } });