How can you listen to click events on a ListView that occur outside of the list items?
Asked Answered
C

5

10

I have a ListView that takes up the entire screen, but sometimes it doesn't have enough items in it to completely cover the ListView widget. I'd like to be able to respond to clicks on that empty space below the last item that doesn't actually contain an item (meaning setOnItemClickListener isn't appropriate).

I've tried setOnClickListener (which they disable for the ListView itself) on a parent view, but clicks don't seem to be reaching it. I also tried setOnTouchListener on the ListView, but that caused some item clicks to not register for some reason. Any ideas on how to accomplish this?

Cordate answered 30/8, 2013 at 0:51 Comment(1)
FWIW, I filed an issue to get the setOnClickListener() restriction lifted, as you make an excellent point: code.google.com/p/android/issues/detail?id=59559Ethelethelbert
C
6

Ran into similiar problem where I needed to close expanded list elements when empty space is clicked. Here is how I solved it.

public class CustomListView extends ListView {

  private OnNoItemClickListener mOnNoItemClickListener;

  public interface OnNoItemClickListener {
    void onNoItemClicked();
  }

  public CustomListView(Context context) {
    super(context);
  }

  public CustomListView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public CustomListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    //check whether the touch hit any elements INCLUDING ListView footer
    if(pointToPosition((int) (ev.getX() * ev.getXPrecision()), 
       (int) (ev.getY() * ev.getYPrecision())) == -1 && ev.getAction() == MotionEvent.ACTION_DOWN) {
      if(mOnNoItemClickListener != null) {
        mOnNoItemClickListener.onNoItemClicked();
      }
    }
    return super.dispatchTouchEvent(ev);
  }

  public void setOnNoItemClickListener(OnNoItemClickListener listener) {
    mOnNoItemClickListener = listener;
  }

}

Then use this CustomListView in your XML file instead of regular ListView and implement OnNoItemClickListener inside your activity / fragment and call mListView.setOnNoItemClickListener(this); in onCreate to enable callback to onNoItemClicked() function.

Note that if your ListView has headers or footers then these are considered as list elements and the onNoItemClicked() won't be called.

Chad answered 28/1, 2015 at 10:54 Comment(0)
W
0

One potential way to achieve is it set your ListView to height="wrap_content" If you do that then you can have override onTouchEvent() for your activity to get the events from when the user touches the empty space.

Layout.xml

<ListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:entries="@array/list" />

Activity.java

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView mList = (ListView)findViewById(R.id.list);
        mList.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int pos,long id) {
                Toast.makeText(v.getContext(), ""+pos, Toast.LENGTH_SHORT).show();
            }
        });
    }
    @Override
    public boolean onTouchEvent(MotionEvent me){
        if(me.getAction() == MotionEvent.ACTION_DOWN){
            Toast.makeText(this, "Empty space", Toast.LENGTH_SHORT).show();
            return true;
        }
        return false;
    }
}

However if you are counting on your ListView height being match_parent for some reason (i.e. background drawable) then this won't be an ideal solution.

Whilst answered 30/8, 2013 at 1:13 Comment(1)
Have you tried this or do you know off hand if ListView interacts well with wrap_content? This just strikes my intuition as something that wouldn't be handled well: won't it try to measure all the ListView's children?Cordate
P
0

Here is example how I did it: https://github.com/mmokrzycki/listview-with-clickable-empty-view

Painless answered 19/5, 2014 at 8:8 Comment(1)
I tried this with my listview which contains rows having EditTexts with TextWatchers. I'm able to catch empty space click events, but the edittext becomes slow while typingDairymaid
A
0

Place an empty linearlayout below the listview by setting an appropriate height to the listview. Place an onClick() method to that linear layout. That must do it.

Aconite answered 26/8, 2014 at 8:16 Comment(0)
B
0

Combining some of the other answers, I came up with this that works well for my use case

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  ... setup list view and other view state
  listView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      if (event.getAction() == MotionEvent.ACTION_DOWN &&
          listView.pointToPosition((int) (event.getX() * event.getXPrecision()), (int) (event.getY() * event.getYPrecision())) == -1) {
        collapseExpandedListItem();
        return true;
      }
      return false;
    }
  });
}
Busk answered 18/1, 2017 at 23:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.