PinnedHeaderLetterListView

Introduction: PinnedHeaderLetterListView 提供一个类似通讯录列表的组件,具备两个主要功能点,1、滑动时首字母会定在顶端,2、右侧有个字母列表,滑动这个列表时,显示选中的字母,同时将列表定位到相应的位置上
More: Author   ReportBugs   DemoAPK   
Tags:
letter-pin-

PinnedHeaderLetterListView 提供一个类似通讯录列表的组件,具备两个主要功能点,1、滑动时首字母会定在顶端,2、右侧有个字母列表,滑动这个列表时,显示选中的字母,同时将列表定位到相应的位置上

效果图

项目简介

lib包为最终提供的公共库
test包为测试用例
其中 lib 里面引用了一个开源库相关代码PinnedHeaderListView,这个开源库已经实现将列表 title 定在顶端的功能,具体介绍可前往查阅

主要类介绍

PinnedHeaderLetterListView.java

PinnedHeaderLetterListView.java为最终提供的组件,继承了PinnedHeaderListView,本质上就是一个 ListView,只不过是在 ListView 的基础上添加了一下操作,在具体使用的时候,跟 ListView 基本一致

    private void initAttrs(AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.pin_letter_list_view);
        mAlphaTextSize = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_alphaTextSize, 16);
        mAlphaTextColor = typedArray.getColor(R.styleable.pin_letter_list_view_alphaTextColor, Color.BLACK);
        mAlphaBackgroudNormalColor = typedArray.getColor(R.styleable.pin_letter_list_view_alphaBackgroundNormalColor, Color.TRANSPARENT);
        mAlphaBackgroudPressedColor = typedArray.getColor(R.styleable.pin_letter_list_view_alphaBackgroundPressedColor, Color.GRAY);
        mAlphaBackgroudColor = mAlphaBackgroudNormalColor;
        mAlphaPaddingLeft = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_alphaPaddingLeft, 0);
        mAlphaPaddingRight = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_alphaPaddingRight, 0);
        mAlphaPaddingTop = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_alphaPaddingTop, 5);
        mAlphaPaddingBottom = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_alphaPaddingBottom, 5);
        String alphaStr = typedArray.getString(R.styleable.pin_letter_list_view_alphaArrays);
        initAlphaList(alphaStr);

        mOverlayTextColor = typedArray.getColor(R.styleable.pin_letter_list_view_overlayTextColor, Color.WHITE);
        mOverlayTextSize = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_overlayTextSize, 40);
        mOverlaySize = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_overlaySize, 80);
        mOverlayColor = typedArray.getColor(R.styleable.pin_letter_list_view_overlayColor, Color.BLACK);
        mOverlayRadius = typedArray.getDimensionPixelSize(R.styleable.pin_letter_list_view_overlayRadius, 10);

        typedArray.recycle();

    }

提供了一些可定制项,例如,选中后提示的字体大小、颜色、弹框的大小、颜色、右侧字母表的相关的定制,对于字母表的数据,用户可直接用 alphaArrays 指定,缺省值为 Adapter 里面获取

PinLetterBaseAdapter.java

继承了SectionedBaseAdapter,扩展了两个方法,用于获取用户滑动字母表时对应的字母在 ListView 中的 postion,使用的时候不需要理会,只要继承这个 PinLetterBaseAdapter 实现自己的 Adapter 就可以了

   /**
     * for locate the position in the whole listview,
     * this index doesn't include with headViewCount
     *
     * @param section
     * @return
     */
    public int getWholePosition(int section) {
        if (section <= 0) {
            return section;
        }
        int index = 0;
        for (int i = 0; i < section; i++) {
            index += getCountForSection(i) + 1;
        }
        return index;
    }

    public int getWholePosition(String letter) {
        if (TextUtils.isEmpty(letter)) {
            return -1;
        }
        int section = -1;
        for (int i = 0, size = list.size(); i < size; i++) {
            if (letter.equals(list.get(i).getLetter())) {
                section = i;
                break;
            }
        }
        return getWholePosition(section);
    }

SectionBaseAdapter.java

这个类是属于 PinnedHeaderListView 开源项目的,在 BaseAdapter 的基础上进行了扩展,将顶部和具体内容的 itemView 分离,让用户自行去实现相应的 View

entity

这里对放进 ListView 的数据结构做了一些约束

PinLetterBaseEntity.java

所有的 item 的最外层数据继承该类

PinLetterBaseItemEntity.java

所有 letter 里面的子 item 数据继承该类

使用方式

在 values.xml 中新建 att.xml

   <?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="pin_letter_list_view">
        <attr name="alphaTextColor" format="color"/>
        <attr name="alphaTextSize" format="dimension"/>
        <attr name="alphaBackgroundNormalColor" format="color"/>
        <attr name="alphaBackgroundPressedColor" format="color"/>
        <attr name="alphaPaddingLeft" format="dimension"/>
        <attr name="alphaPaddingRight" format="dimension"/>
        <attr name="alphaPaddingTop" format="dimension"/>
        <attr name="alphaPaddingBottom" format="dimension"/>
        <attr name="overlaySize" format="dimension"/>
        <attr name="overlayColor" format="color"/>
        <attr name="overlayTextSize" format="dimension"/>
        <attr name="overlayTextColor" format="color"/>
        <attr name="overlayRadius" format="dimension"/>
        <attr name="alphaArrays" format="string"/>
    </declare-styleable>
</resources>

在 layout.xml 文件中

   <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:pinletter="http://schemas.android.com/apk/res/com.ulex.apps.pinnedheaderletterlistview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <com.ulex.apps.pinnedheaderletterlistview.lib.PinnedHeaderLetterListView
        android:id="@+id/pinned_indicated_listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:listSelector="@null"
        android:cacheColorHint="@android:color/transparent"
        pinletter:overlayTextColor="@android:color/holo_red_dark"
        pinletter:overlayColor="@android:color/holo_blue_bright"
        pinletter:alphaArrays="#ABCDEFGHIJKLMNOPQRSTUVWXYZ"/>

</RelativeLayout>

编写实体类

继承 PinLetterBaseEntity.java、PinLetterBaseItemEntity.java 实现相应的实体类

继承PinLetterBaseAdapter实现 Adapter 类

  public class ContactsPinLetterListAdapter extends PinLetterBaseAdapter {

    public ContactsPinLetterListAdapter(List<ContactsPinLetterEntity> list) {
        super(list);
    }

    @Override
    public Object getItem(int section, int position) {
        return null;
    }

    @Override
    public long getItemId(int section, int position) {
        return 0;
    }

    @Override
    public int getSectionCount() {
        return list.size();
    }

    @Override
    public int getCountForSection(int section) {
        return list.get(section).getItemEntityList().size();
    }

    @Override
    public View getItemView(int section, int position, View convertView, ViewGroup parent) {
        ItemViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ItemViewHolder(parent);
            convertView = viewHolder.getView();
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ItemViewHolder) convertView.getTag();
        }
        ContactsPinLetterItemEntity entity = (ContactsPinLetterItemEntity) list.get(section).getItemEntityList().get(position);
        viewHolder.render(entity.getName());
        return convertView;
    }

    @Override
    public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
        HeaderViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new HeaderViewHolder(parent);
            convertView = viewHolder.getView();
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (HeaderViewHolder) convertView.getTag();
        }
        ContactsPinLetterEntity entity = (ContactsPinLetterEntity) list.get(section);
        viewHolder.render(entity.getLetter());
        return convertView;
    }

最后

    List<ContactsPinLetterEntity> list = ContactsPinLetterModel.getContactsList();
        ContactsPinLetterListAdapter listAdapter = new ContactsPinLetterListAdapter(list);
        TextView textView = new TextView(this);
        textView.setText("This is a headerView...");
        AbsListView.LayoutParams params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 200);
        textView.setLayoutParams(params);
        listView.addHeaderView(textView);
        listView.setAdapter(listAdapter);
Apps
About Me
GitHub: Trinea
Facebook: Dev Tools