How to get the location (on screen) of a line in a list

I implemented some gesture detection code so that I could detect when a line was drawn in my list (which is in FrameLayout).

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { int itemId = MainActivity.this.getListView().pointToPosition((int) e1.getX(),(int) e1.getY()); Offer order = (Offer)MainActivity.this.getListView().getAdapter().getItem(itemId); View v = MainActivity.this.getListView().getChildAt(itemId); } } 

I want to display a view on top of a vertex row with a set of context sensitive options for that row.

My problems are that the following methods:

 v.getTop() v.getBottom() 

return the correct values ​​only before scrolling the view. Perhaps I could do some calculations to work out offsets using scroll positions, etc., but I also noticed that I only get values ​​when I scroll the line that is visible on the screen to start. If I scroll down the list and then scroll the line (which was not originally off the screen), then these methods return null values.

The methods below seem to suffer from the same problem ...

 v.getLocationOnScreen(loc) v.getLocationInWindow(loc) 

Ultimately, I am looking to find the distance between the top of the visible listView and the row that was skipped. Then I will use this distance to add the view to the parent FrameLayout with the appropriate height fill (so that it covers the line with slots).

Any help would be greatly appreciated!

+7
android
Jan 26
source share
3 answers

There are two different ways to index ListView items, the location in the adapter or the visible location on the screen. The item will always be in the same place inside the adapter (unless you change it). The index in view.getChildAt () will change depending on what is visible on the screen.

The position returned by pointToPosition is the position inside the adapter. If you want a physical view, you need to consider if the view scrolls. Try the following:

 int adapterIndex = MainActivity.this.getListView().pointToPosition((int) e1.getX(),(int) e1.getY()); int firstViewItemIndex = MainActivity.this.getListView().getFirstVisiblePosition(); int viewIndex = adapterIndex - firstViewItemIndex; View v = MainActivity.this.getListView().getChildAt(viewIndex); 
+17
Jan 26 '10 at 16:32
source share

I solved it, but it seems like a hack and probably not the most efficient implementation. Surely there should be a cleaner way to do this using the Android API?

In the code below, I added a HashMap to my ArrayAdaptor array to keep track of which views on the screen contain strings (since they are recycled when scrolling through the list)

All the changes that I made to the source adapter were described below.

  class RestaurantAdapter extends ArrayAdapter<Offer> { Map hash = null; //HashMap to keep track of rowId and on screen View RestaurantAdapter() { super(MainActivity.this, android.R.layout.simple_list_item_1, model); hash = new HashMap(); //instantiate HashMap in constructor } //method to return correct View on screen for row id public View getViewOnScreen(int rowId) { return (View)hash.get(rowId); } public View getView(int position, View convertView, ViewGroup parent) { View row=convertView; hash.put(position, convertView); // add/update view for row position as it is recycled RestaurantWrapper wrapper=null; if (row==null) { LayoutInflater inflater=getLayoutInflater(); row=inflater.inflate(R.layout.row, parent, false); wrapper=new RestaurantWrapper(row); row.setTag(wrapper); } else { wrapper=(RestaurantWrapper)row.getTag(); } wrapper.populateFrom(model.get(position)); return(row); } } 
+1
Jan 27 '10 at
source share

This is the best way to find which row has been affected.

  Rect rect = new Rect(); int childCount = mListView.getChildCount(); int[] listViewCoords = new int[2]; mListView.getLocationOnScreen(listViewCoords); int listX = (int) event.getRawX() - listViewCoords[0]; int listY = (int) event.getRawY() - listViewCoords[1]; View child; for (int i = 0; i < childCount; i++) { child = mListView.getChildAt(i); child.getHitRect(rect); if (rect.contains(listX, listY)) { mDownView = child; break; } } 

You can use this in the onTouch method in the ACTION_DOWN event. Hey.

+1
Apr 14 '14 at 12:10
source share



All Articles