Issues with Fast Scroll in Android 4.4
Asked Answered
L

3

18

I wrote an app which contains a ListView in its layout that supports fast scroll (i.e. dragging the scroll bar slider allows you to quickly scroll up or down the list). This worked perfectly in all version of Jelly Bean (4.1-4.3). However, after I updated to Kit Kat, fast scroll no longer works, and my scroll bar is just a normal scroll bar. However, if I switch out of my app and back in, fast scroll appears. How do I get fast scroll to consistently work in Kit Kat? I;ve copied and pasted my list view adapter code below:

// Adds section popup for fast scroll
class NameListAdapter extends  SimpleAdapter implements SectionIndexer  {
    HashMap<String, Integer> alphaIndexer;
    private String[] sections;
    private ArrayList<String> sectionList;
    private List<HashMap<String, String>> data = null;

    public NameListAdapter (Context context, List<HashMap<String, String>> data, 
            int resource, String[] from, int[] to) {
        super(context, data, resource, from, to);
        alphaIndexer = new HashMap<String, Integer>();
        sectionList = new ArrayList<String>();
        this.data = data;
        int size = data.size();

        for (int i = 0; i < size; i++) {
            HashMap<String, String> myData = (HashMap <String, String>) data.get(i);
            // Get first character
            String ch = myData.get("name").substring(0, 1);
            // Convert character to upper case
            ch = ch.toUpperCase();

            // Put first char/index into our HashMap
            if (!alphaIndexer.containsKey(ch)) {
                alphaIndexer.put(ch, i);
                sectionList.add(ch);
            }
        }
        sections = new String[sectionList.size()];
        sectionList.toArray(sections);
    }

    @Override
    public int getPositionForSection(int section) {
        if (section >= sections.length) {
            return getCount() - 1;
        }

        return alphaIndexer.get(sections[section]);
    }

    @Override
    public int getSectionForPosition(int pos) {

        if (pos > data.size()) {
            return 0;
        }

        HashMap<String, String> myData = (HashMap <String, String>) data.get(pos);
        String ch = myData.get("name").substring(0, 1);
        // Convert character to upper case
        ch = ch.toUpperCase();

        for (int i = 0; i < sectionList.size(); i++) {
            if (sectionList.get(i).equals(ch)) {
                return i;
            }
        }
        return 0;

    }

    @Override
    public Object[] getSections() {
        return sections;
    }
}
Lorimer answered 8/12, 2013 at 0:21 Comment(2)
I opened a bug about this so feel free to star it. code.google.com/p/android/issues/…Abercromby
This appears to be resolved in Android v4.4.3.Vevina
Y
13

Having the same issue here, it's not a good solution, but for now you can do :

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    view.setFastScrollAlwaysVisible(true);
}

This will keep your fast scroller on all the time.

Yelenayelich answered 11/12, 2013 at 9:36 Comment(2)
This has worked for me, as well. I'm suspecting it's a bug in KitKat. It works correctly in my Jelly Bean devices.Oleaceous
It seems for KitKat devices, this is the only real solution to the problem. You should consider doing an equality check for version: as it is fixed in later versions: code.google.com/p/android/issues/detail?id=63545Buller
P
2

Here's a slightly improved work-around which is similar to mikejonesguy's answer

Basically you set fast scroll always visible when the list scroll is not idle. When the list stops scrolling you start a timer and turn fast scroll off after a period of time. This duplicates the way it used to work on older versions of android.

Hope it helps

//fix for kitkat bug in fast scroll
Runnable delayedFastScrollFixRunnable = new Runnable()
{
    @Override
    public void run()
    {
        if (listView != null && fastScrollAlwaysVisible)
        {
            listView.setFastScrollAlwaysVisible(false);
            fastScrollAlwaysVisible = false;
        }
    }
};
Handler delayedFastScrollFixHandler = new Handler();
boolean fastScrollAlwaysVisible = false;

mList.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) 
    {
       //fix an issue with 4.4 not showing fast scroll
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
    {
        if (scrollState == SCROLL_STATE_IDLE)
        {
            if (fastScrollAlwaysVisible)
            {
                delayedFastScrollFixHandler.postDelayed(delayedFastScrollFixRunnable, 750);
            }
        }
        else
        {
            if (!fastScrollAlwaysVisible)
            {
                delayedFastScrollFixHandler.removeCallbacks(delayedFastScrollFixRunnable);
                listView.setFastScrollAlwaysVisible(true);
                fastScrollAlwaysVisible = true;
            }
        }
    }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) 
    {
    }
});
Perretta answered 29/1, 2014 at 11:30 Comment(1)
Like mikejonesguy`s solution, this one hides the fast scroller while it is being used (just with a little delay). Probably there is some error with your code? Also you need to move the list first, before the fast scroller can be used.Buller
L
1

It's a known issue (reported here and here), and that it got fixed as of 4.4.3 .

Here's a workaround:

  public static void setFastScrolledEnabled(final AdapterView<?> adapterView,final boolean enable)
    {
    final GridView gridView;
    final ListView listView;
    if(adapterView instanceof GridView)
      {
      gridView=(GridView)adapterView;
      listView=null;
      }
    else if(adapterView instanceof ListView)
      {
      listView=(ListView)adapterView;
      gridView=null;
      }
    else throw new UnsupportedOperationException("setFastScrolledEnabled is only available for gridView/listView");
    if(Build.VERSION.SDK_INT==VERSION_CODES.KITKAT)
      adapterView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
        {
          @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
          @Override
          public void onGlobalLayout()
            {
            if(gridView!=null)
              gridView.setFastScrollEnabled(enable);
            else if(listView!=null)
              listView.setFastScrollEnabled(enable);
            adapterView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
    else if(gridView!=null)
      gridView.setFastScrollEnabled(enable);
    else if(listView!=null)
      listView.setFastScrollEnabled(enable);
    }
Letourneau answered 2/5, 2014 at 13:1 Comment(3)
This is no real workaround, as it only works for the first time (up until you set another adapter to the ListView). Nonetheless, it tries to touch the problem at it's root.Buller
@Buller I know. I have no idea how to solve this completely . If you find a way, can you please let me know? maybe they've fixed it on 4.4.3 ?Letourneau
It seems as if they have: code.google.com/p/android/issues/detail?id=63545Buller

© 2022 - 2024 — McMap. All rights reserved.