うさがにっき

読書感想文とプログラムのこと書いてきます

AndroidでFastScrollとインデックスラベルのついたscrollの作り方

概要

こんな感じのインデックスラベルのついたスクロールの作り方
スクロールをドラッグすると、ラベルが表示される
f:id:tiro105:20140623162136p:plain

詳細

FastScrollを実装するには、ListViewのsetFastScrollEnabled()をtrueにする

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        ListView listView = getListView();
        // fastScroll有効化
        listView.setFastScrollEnabled(true);
        // スクロールを常に表示するように
        listView.setFastScrollAlwaysVisible(true);

        CustomAdapter adapter = new CustomAdapter(getActivity(),
                android.R.layout.simple_list_item_1, fruits);

        setListAdapter(adapter);
    }


インデックスラベルを表示するにはSectionIndexerを実装する

    public static class CustomAdapter extends ArrayAdapter<CustomAdapter.DataItem> implements
            SectionIndexer {


SectionIndexerでは以下のメソッドを実装する必要がある
getPositionForSectionではインデックスラベルに対応するリストビューの位置を返す
getSectionForPositionではリストの位置に対応するインデックスラベルのインデックスを返す
getSectionsではインデックスラベルをtoString()をcallした結果、ラベルとなるObject配列を返す

        @Override
        public int getPositionForSection(int sectionIndex) {
            // セクションに対応するリストの位置
            return mSections[sectionIndex].position;
        }

        @Override
        public int getSectionForPosition(int position) {
            // リストの位置に対応するセクションのインデックスを返す
            return getItem(position).section;
        }

        @Override
        public Object[] getSections() {
            // SectionIndexerでは、対応するObjectに対してtoString()を
            // 呼んだ結果をインデックスラベルとして表示する
            return mSections;
        }


上記に当てはまるようにadapterで必要なデータを作る

        public CustomAdapter(Context context, int resource, String[] data) {
            super(context, resource, new ArrayList<DataItem>());

            // ソート
            Arrays.sort(data, new Comparator<String>() {

                @Override
                public int compare(String lhs, String rhs) {
                    return lhs.compareTo(rhs);
                }
            });

            // SectionIndexer用
            ArrayList<SectionItem> sections = new ArrayList<SectionItem>();

            String oldLabel = null;
            int section = -1;
            for (String s : data) {
                if (TextUtils.isEmpty(s)) {
                    return;
                }

                // 頭文字を取得
                String newLabel = s.substring(0, 1).toUpperCase(Locale.ENGLISH);

                // 頭文字が変わった
                if (oldLabel == null || !oldLabel.equals(newLabel)) {
                    section = sections.size();
                    // SectionIndexerに表示するラベルと区切りの行の位置を保持
                    sections.add(new SectionItem(newLabel, getCount()));
                    // 区切りの行を入れる
                    add(new DataItem(newLabel, section, false));
                }

                // データを追加
                add(new DataItem(s, section, true));
                oldLabel = newLabel;
            }

            // SectionIndexer用のデータを配列で保持
            mSections = sections.toArray(new SectionItem[] {});
        }