如何为 ListView 项目获取()

How to getY() for ListView items

在水平 LinearLayout(匹配屏幕宽度)中,我有两个 ListView 实例(带有动态列表项)和一个 TextView 实例。使用 TextView 作为 canvas,我想绘制(Bezier)线连接左侧 ListView 中的选定列表项与右侧 ListView 中的所有列表项,反之亦然。现在完全有可能被选中的列表项或另一侧的任何列表项都在 ListView 的可见区域之外。在这种情况下,我想只在可见的范围内绘制这些线(从 above/below 进入或离开 above/below)。为了绘制这些线,我需要在每条线的开头和结尾处设置 x 和 y 值。 x 只是 textView.getLeft() 和 textView.getRight(),但 y 取决于两个列表的当前滚动位置。

我的问题是获取特定 ListView 项目的当前 y 值:

list.getChildAt(indexOfCurrentlySelectedItem).getY()

我需要在列出列表后访问这些值。我需要确定哪些列表项是可见的,哪些列表项是不可见的(不可见的列表项是否具有 y 值?视图?可回收视图(使用持有人模式)?)。我需要能够遍历我为了将这些 y 值传递给我的 TextView 的 onDraw 方法的列表。最后我需要安装一个机制来在滚动发生后重新绘制线条。

如何获取当前的 y 值(布局后和滚动后)?我是否必须跟踪 OnScrollListener 中的可见位置?我是否必须在 OnGlobalLayoutListener 中监听列表布局的结尾?我(还)是否必须在 OnGlobalLayoutListener 中为每个列表项监听列表项布局的结尾?

好的,我找到了一个很好的解决方案:OnScrollListener 提供了我所需要的,而这里不需要 OnGlobalLayoutListener。

public class ArrayListAdapter extends ArrayAdapter<String>
    implements AbsListView.OnScrollListener

...

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}

@Override
public synchronized void onScroll(final AbsListView listView, int firstVisibleItem,
                                  int visibleItemCount, int totalItemCount) {
    List<Integer>yList = new ArrayList<>();
    int checkedPosition = listView.getCheckedItemPosition();
    double yChecked = 0;

    for (int pos = 0; pos < totalItemCount; pos++) {
        CheckedTextView tv = (CheckedTextView) this
                .getViewByPosition(pos, listView, firstVisibleItem,
                        firstVisibleItem + visibleItemCount - 1);
        if (pos == checkedPosition) {
            yChecked = tv.getY();
        }
        yList.add(pos, tv.getY());
    }        
    // Here I pass the fresh y-values to the fragment holding the 
    // two ListViews. After some further calculations the fragment
    // passes the data to the TextView where it is stored and
    // this.invalidate is called to eventually trigger the onDraw method.
    originalFragment.setScrollData(yList, yChecked);
}

private View getViewByPosition(int pos, AbsListView listView, int firstVisibleItem,
                               int lastVisibleItem) {
    if (pos < firstVisibleItem || pos > lastVisibleItem) {
        // The next line is the only downside of this solution I have
        // found so far. If the convertView of the getView(int
        // position, View convertView, ViewGroup parent) method is null
        // the holder pattern I applied in my adapter becomes useless.
        // In my case the recreation of the CheckedTextViews is fast
        // enough though.
        return listView.getAdapter().getView(pos, null, listView);
    } else {
        return listView.getChildAt(pos - firstVisibleItem);
    }
}