在Android中按像素滚动ListView

8
我想在Android中通过像素数来滚动ListView。例如,我想向下滚动列表10个像素(以便列表上的第一个项目有其顶部的10个像素行被隐藏)。
我认为显然可见的scrollByscrollTo方法可以完成这项工作,但它们不能,相反它们错误地滚动整个列表(实际上,即使我用手指滚动了列表,getScrollY始终返回零)。
我的做法是捕获Trackball事件,并根据Trackball的运动平稳地滚动listview。

这就是 scrollby 应该做的事情。你能发一下你的 Java 代码吗? - Matthew
2
我觉得scrollBy在某种程度上会搞乱listView。我也一直在尝试使用它。它会将触摸事件按照scrollBy的量进行移动...所以如果你设置y轴滚动10个像素,那么列表上的下一个触摸事件将在实际触摸位置的下方10个像素处标记...很抱歉,我不知道有更好的方法,但或许可以通过listView的onTouch方法来补偿这些问题。 - DArkO
5个回答

12

ListView小部件中滚动的支持方法是:

mListView.smoothScrollToPosition(position);

http://developer.android.com/reference/android/widget/AbsListView.html#smoothScrollToPosition(int)

然而,由于您特别提到要垂直偏移视图,因此您必须调用:

mListView.setSelectionFromTop(position, yOffset);

http://developer.android.com/reference/android/widget/ListView.html#setSelectionFromTop(int,%20int)

请注意,您还可以使用smoothScrollByOffset(yOffset)。但是它仅支持API >= 11。

http://developer.android.com/reference/android/widget/ListView.html#smoothScrollByOffset(int)


另外,smoothScroolToPosition仅适用于API >= 8 :( - Thomas Ahle

10

如果您查看添加在API 19中的scrollListBy()方法的源代码,您会发现可以使用包作用域下的trackMotionScroll方法。

public class FutureListView {

    private final ListView mView;

    public FutureListView(ListView view) {
        mView = view;
    }

    /**
     * Scrolls the list items within the view by a specified number of pixels.
     *
     * @param y the amount of pixels to scroll by vertically
     */
    public void scrollListBy(int y) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mView.scrollListBy(y);
        } else {
            // scrollListBy just calls trackMotionScroll
            trackMotionScroll(-y, -y);
        }
    }

    private void trackMotionScroll(int deltaY, int incrementalDeltaY) {
        try {
            Method method = AbsListView.class.getDeclaredMethod("trackMotionScroll", int.class, int.class);
            method.setAccessible(true);
            method.invoke(mView, deltaY, incrementalDeltaY);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        };
    }
}

确保硬件加速已开启。http://developer.android.com/guide/topics/graphics/hardware-accel.html - enl8enmentnow

3
这是我 ListView 子类的一些代码。它可以很容易地适应于 Activity 代码中。 getListItemsHeight() 返回列表的总像素高度,并使用每个项目的垂直像素偏移量填充数组。虽然这些信息是有效的,但是 getListScrollY() 返回当前垂直像素滚动位置,scrollListToY() 将列表滚动到像素位置。 如果列表的大小或内容发生更改,则必须再次调用 getListItemsHeight()
private int m_nItemCount;
private int[] m_nItemOffY;

private int getListItemsHeight() 
{  
    ListAdapter adapter = getAdapter();  
    m_nItemCount = adapter.getCount();
    int height = 0;
    int i;

    m_nItemOffY = new int[m_nItemCount];

    for(i = 0; i< m_nItemCount; ++i){ 
        View view  = adapter.getView(i, null, this);  

        view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));  

        m_nItemOffY[i] = height;
        height += view.getMeasuredHeight();
    }  

    return height;  
}  

private int getListScrollY()
{
    int pos, nScrollY, nItemY;
    View view;

    pos = getFirstVisiblePosition();
    view = getChildAt(0);
    nItemY = view.getTop();
    nScrollY = m_nItemOffY[pos] - nItemY;

    return nScrollY;
}

private void scrollListToY(int nScrollY)
{
    int i, off;

    for(i = 0; i < m_nItemCount; ++i){
        off = m_nItemOffY[i] - nScrollY;
        if(off >= 0){
            setSelectionFromTop(i, off);
            break;
        }
    }
}

1

目前来看,ListViewCompat 可能是更好的解决方案。

android.support.v4.widget.ListViewCompat.scrollListBy(@NonNull ListView listView, int y)

0
如果你想按像素移动,那么可以使用这个。
public void scrollBy(ListView l, int px){
    l.setSelectionFromTop(l.getFirstVisiblePosition(),l.getChildAt(0).getTop() - px);
}

这适用于具有大标题的所有内容


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接