Как получить местоположение (на экране) строки в просмотре списка - PullRequest
7 голосов
/ 26 января 2010

Я реализовал некоторый код для обнаружения жестов, чтобы я мог определять, когда строка в моем списке просмотра (которая находится в 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)

В конечном счете, я ищу, чтобы найти расстояние между вершиной видимого listView и строкой, которая была проведена. Затем я буду использовать это расстояние, чтобы добавить представление к родительскому FrameLayout с соответствующим отступом по высоте (чтобы оно охватывало измененную строку).

Любая помощь будет высоко ценится!

Ответы [ 3 ]

17 голосов
/ 26 января 2010

Существует два разных способа индексации элементов 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 голос
/ 14 апреля 2014

Это лучший способ, который я нашел, чтобы определить, какая строка была затронута.

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

Вы можете использовать это в методе onTouch в событии ACTION_DOWN. Привет.

1 голос
/ 27 января 2010

Я решил это, но это похоже на хакерство и, вероятно, не самая эффективная реализация. Конечно, должен быть более чистый способ сделать это с помощью API Android?

В приведенном ниже коде я добавил HashMap в свой ArrayAdaptor, чтобы отслеживать, какие на экранах представления содержат какие строки (поскольку они перезаписываются при прокрутке списка)

Все изменения, которые я внес в свой оригинальный адаптер, были прокомментированы ниже.

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


        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...