2

Background

I've noticed an issue (link here) when adding a header view inside a ListView, in case the ListViewis inside a SwipeRefreshLayout.

The problem

The issue is that if the header view is partially visible, and you scroll up, you will see the circular view of the SwipeRefreshLayout.

You can check the link above to see a video of what I'm talking about.

Sample code

Here's how to reproduce this issue (you can check the link above in case you don't want to copy-paste) :

MainActivity.java

public class MainActivity extends ActionBarActivity
  {
  @Override
  protected void onCreate(final Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final ListView listView=(ListView)findViewById(android.R.id.list);
    final TextView tv=new TextView(this);
    tv.setText("a very large header view");
    tv.setTextSize(70);
    listView.addHeaderView(tv);
    final SwipeRefreshLayout swipeRefreshLayout=(SwipeRefreshLayout)findViewById(R.id.swipeToRefreshLayout);
    swipeRefreshLayout.setOnRefreshListener(new OnRefreshListener()
      {
        @Override
        public void onRefresh()
          {
          new Handler().postDelayed(new Runnable()
            {
              @Override
              public void run()
                {
                swipeRefreshLayout.setRefreshing(false);
                }
            },1000);
          }
      });
    final ArrayList<String> arrayList=new ArrayList<String>();
    for(int i=0;i<1000;++i)
      arrayList.add(Integer.toString(i));
    listView.setAdapter(new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,arrayList));
    }
  }

res/layout/activity_main.xml

<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/swipeToRefreshLayout"
    android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_height="match_parent" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="@android:color/transparent"
        android:fastScrollEnabled="true"
        android:footerDividersEnabled="true"
        android:headerDividersEnabled="true"
        android:paddingEnd="4dp"
        android:paddingLeft="4dp"
        android:paddingRight="4dp"
        android:paddingStart="4dp"
        android:scrollingCache="false"
        android:smoothScrollbar="false"
        android:textFilterEnabled="true"/>

</android.support.v4.widget.SwipeRefreshLayout>

The question

Is there a way to solve this problem?

I guess I could use multi-types for the listView , but is there maybe another solution that is more elegant, simple or better in any other way?

android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • Yes, but then it's above the ListView, which doesn't allow to view the circular view of the SwipeRefreshLayout where it belongs. Also, the TextView won't be scrollable and part of the listView this way. – android developer Nov 20 '14 at 20:16

2 Answers2

1

EDIT: It seems it occurs even if I use multi-type items for the ListView. Later I've discovered that it just always occur for the first item on the listView.

If the first item is large enough, it will be easy to reproduce.

So, for now, there is a simple workaround:

Before using the listview in any way, first add an empty view as a header view, and never remove it:

listView.addHeaderView(new View(this));

This way, as the view is practically invisible, the bug won't be shown to the user.

This is just a workaround, but I think the best thing should be to fix this issue.

android developer
  • 114,585
  • 152
  • 739
  • 1,270
1

Very similar to Android issue 78375. Try to override SwipeRefreshLayout#canChildScrollUp

@Override
public boolean canChildScrollUp() {
    View target = getChildAt(0);
    if (target instanceof AbsListView) {
        final AbsListView absListView = (AbsListView) target;
        return absListView.getChildCount() > 0
                && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                .getTop() < absListView.getPaddingTop());
    } else {
        return target.getScrollY() > 0;
    }
}
ls.illarionov
  • 741
  • 1
  • 10
  • 12
  • Thank you. Will now mark this as the correct answer, till Google fixes this issue. Say, if you are good in RecyclerView, can you please check this out: http://stackoverflow.com/questions/27798212/how-to-add-a-fast-scroller-to-the-recyclerview ? – android developer Jan 25 '15 at 23:44