Create easy alphabetical scrolling in ListView?

2020-01-30 07:16发布

I'm looking to emulate the functionality in the latest Music app, namely the nice little cursor that pops up which allows one to scroll super fast to the artist/album/track they're looking for:

"Super Scrolling" Regular Scrolling

Is there a method to enable functionality like this in a ListView in the Android SDK?

6条回答
Root(大扎)
2楼-- · 2020-01-30 07:35

Here is the subclass of ArrayAdapter I'm using. Note that the objects I pass in has already been sorted alphabetically, with Collections.sort(objects).

class SectionIndexingArrayAdapter<T> extends ArrayAdapter<T> implements
        SectionIndexer {

    HashMap<String, Integer> sectionsMap = new HashMap<String, Integer>();
    ArrayList<String> sectionsList = new ArrayList<String>();

    ArrayList<Integer> sectionForPosition = new ArrayList<Integer>();
    ArrayList<Integer> positionForSection = new ArrayList<Integer>();

    public SectionIndexingArrayAdapter(Context context, int textViewResourceId,
            List<T> objects) {
        super(context, textViewResourceId, objects);

        // Note that List<T> objects has already been sorted alphabetically
        // e.g. with Collections.sort(objects) **before** being passed to
        // this constructor.

        // Figure out what the sections should be (one section per unique
        // initial letter, to accommodate letters that might be missing,
        // or characters like ,)
        for (int i = 0; i < objects.size(); i++) {
            String objectString = objects.get(i).toString();
            if (objectString.length() > 0) {
                String firstLetter = objectString.substring(0, 1).toUpperCase();
                if (!sectionsMap.containsKey(firstLetter)) {
                    sectionsMap.put(firstLetter, sectionsMap.size());
                    sectionsList.add(firstLetter);
                }
            }
        }

        // Calculate the section for each position in the list.
        for (int i = 0; i < objects.size(); i++) {
            String objectString = objects.get(i).toString();
            if (objectString.length() > 0) {
                String firstLetter = objectString.substring(0, 1).toUpperCase();
                if (sectionsMap.containsKey(firstLetter)) {
                    sectionForPosition.add(sectionsMap.get(firstLetter));
                } else
                    sectionForPosition.add(0);
            } else
                sectionForPosition.add(0);
        }

        // Calculate the first position where each section begins.
        for (int i = 0; i < sectionsMap.size(); i++)
            positionForSection.add(0);
        for (int i = 0; i < sectionsMap.size(); i++) {
            for (int j = 0; j < objects.size(); j++) {
                Integer section = sectionForPosition.get(j);
                if (section == i) {
                    positionForSection.set(i, j);
                    break;
                }
            }
        }
    }

    // The interface methods.

    public int getPositionForSection(int section) {
        return positionForSection.get(section);
    }

    public int getSectionForPosition(int position) {
        return sectionForPosition.get(position);
    }

    public Object[] getSections() {
        return sectionsList.toArray();
    }
}
查看更多
甜甜的少女心
4楼-- · 2020-01-30 07:46

I found a great solution here... Works great with a huge list... Nice and fast... no loading time.

@Override
public int getPositionForSection(int section)
{
    log.info("Get position for section");

    for (int i = 0; i < this.getCount(); i++)
    {
        if (this.getItem(i).length() > 0)
        {
            String item = this.getItem(i).toUpperCase();
            if (item.charAt(0) == sections.charAt(section))
            {
                return i;
            }
        }
    }
    return 0;
}

@Override
public int getSectionForPosition(int arg0)
{
    log.info("Get section");

    return 0;
}

@Override
public Object[] getSections()
{
    log.info("Get sections");

    String[] sectionsArr = new String[sections.length()];

    for (int i = 0; i < sections.length(); i++)
    {
        sectionsArr[i] = "" + sections.charAt(i);
    }
    return sectionsArr;
}
查看更多
霸刀☆藐视天下
5楼-- · 2020-01-30 07:47

Have your list adapter implement SectionIndexer. The music app also makes use of AlphabetIndexer to do some of the heavy lifting. Also use setFastScrollEnabled(true) on the actual ListView to enable this.

Edit: If you're not using a CursorAdapter, you won't be able to use AlphabetIndexer. You might try looking at the implementation here and seeing how hard it would be to adapt it to work with an ArrayAdapter.

查看更多
手持菜刀,她持情操
6楼-- · 2020-01-30 07:55

To collect the details about the items shown in a listview, you can do this:

@Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {

            albumButton.setText(songs.get(firstVisibleItem).getAlbum());

        }

Isn't this a bit simpler? Here, 'songs' is an arraylist of Song objects. You can even get the last visible item by adding firstVisibleItem + visibleItemCount. I found this technique to be very useful. So then you would get the first letter of each song. I assume the gray box containing the letter in the music app you posted is a dialog box of sorts?

Anyway, hope this helps. I realise I'm late, but this is for future people

查看更多
可以哭但决不认输i
7楼-- · 2020-01-30 07:57

On anddev.org I found this tutorial: Alphabetic FastScroll ListView - similar to Contacts

It also contains a short demo-video

Hope it helps!

查看更多
登录 后发表回答