如何在listview中获取行的位置(在屏幕上)

时间:2010-01-26 13:43:23

标签: android

我已经实现了一些手势检测代码,这样我就可以检测到listview(位于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);
    }
}

我想在滑动行的顶部显示一个视图,其中包含该行的一组上下文相关选项。

我的问题是以下方法:

v.getTop()
v.getBottom()

仅在滚动视图之前返回正确的值。我可以做一些计算来计算使用滚动位置等的偏移量,但我也注意到,当我在屏幕上滑动可见的行时,我只获取值。如果我向下滚动列表然后滑动一行(原来不在屏幕外),那么这些方法将返回空值。

下面的方法似乎也遇到了同样的问题...

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

最终,我希望找到可见列表顶部与已刷过的行之间的距离。然后,我将使用此距离将父视图添加到具有适当高度填充的父FrameLayout(以便它覆盖滑动的行)。

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:17)

有两种不同的方法可以通过适配器中的位置或屏幕上的可见位置索引ListView项目。项目将始终位于适配器中的相同位置(除非您更改列表)。 view.getChildAt()的索引将根据屏幕上可见的内容而有所不同。

pointToPosition返回的位置是适配器中的位置。如果要获取物理视图,则需要考虑是否滚动视图。试试这个:

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);

答案 1 :(得分:1)

我已经解决了这个问题,但感觉有点像黑客,可能不是最有效的实现。当然必须有一种更简洁的方法来使用Android API吗?

在下面的代码中,我在我的ArrayAdaptor中添加了一个HashMap,以跟踪哪些屏幕视图中包含哪些行(因为这些行在滚动列表时被回收)

我对原始适配器所做的所有更改都在下面发表了评论。

 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);
            }


        }

答案 2 :(得分:1)

这是我发现检测哪一行被触摸的最佳方法。

            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;
                }
            }

您可以在ACTION_DOWN事件的onTouch方法中使用它。问候。