24

私はしばらくの間 S​​moothScrollToPositionFromTop() を機能させようとしましたが、常に正しい位置にスクロールするとは限りません。

横に 10 個のボタンがあるレイアウトに ListView (10 個の項目) があるので、リスト内のすべての項目にスクロールできます。通常、1 ポジション前後にスクロールすると正常に動作しますが、3 ポジション以上前後にスクロールしようとすると、ListView が選択した位置で正確に終了しません。失敗すると、通常は 0.5 から 1.5 のアイテムがオフになり、スクロールが失敗したときは実際には予測できません。

notifyDataSetChanged が android で機能しない後、 SmoothScrollToPositionもチェックアウトしましたが、この修正は機能せず、データを変更しません。

選択したリストアイテムに自動的にスクロールしたいのですが、方法がわかりません。誰かが以前にこの問題を抱えていて、それを修正する方法を知っていますか?

4

5 に答える 5

52

これは既知のバグです。https://code.google.com/p/android/issues/detail?id=36062を参照してください

ただし、発生する可能性のあるすべてのエッジケースに対処するこの回避策を実装しました。

最初に を呼び出しsmothScrollToPositionFromTop(position)、スクロールが終了したら を呼び出しますsetSelection(position)。後者の呼び出しは、目的の位置に直接ジャンプすることにより、不完全なスクロールを修正します。そうすることで、ユーザーはまだこの位置までアニメーションでスクロールされているという印象を受けます。

この回避策を 2 つのヘルパー メソッド内に実装しました。

SmoothScrollToPositionFromTop()

public static void smoothScrollToPositionFromTop(final AbsListView view, final int position) {
    View child = getChildAtPosition(view, position);
    // There's no need to scroll if child is already at top or view is already scrolled to its end
    if ((child != null) && ((child.getTop() == 0) || ((child.getTop() > 0) && !view.canScrollVertically(1)))) {
        return;
    }

    view.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(final AbsListView view, final int scrollState) {
            if (scrollState == SCROLL_STATE_IDLE) {
                view.setOnScrollListener(null);

                // Fix for scrolling bug
                new Handler().post(new Runnable() {
                    @Override
                    public void run() {
                        view.setSelection(position);
                    }
                });
            }
        }

        @Override
        public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
                                 final int totalItemCount) { }
    });

    // Perform scrolling to position
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            view.smoothScrollToPositionFromTop(position, 0);
        }
    });
}

getChildAtPosition()

public static View getChildAtPosition(final AdapterView view, final int position) {
    final int index = position - view.getFirstVisiblePosition();
    if ((index >= 0) && (index < view.getChildCount())) {
        return view.getChildAt(index);
    } else {
        return null;
    }
}
于 2014-01-08T14:02:18.817 に答える
3

これがソリューションの実装です。

    void smoothScrollToPositionFromTopWithBugWorkAround(final AbsListView listView,
                                                    final int position,
                                                    final int offset, 
                                                    final int duration){

    //the bug workaround involves listening to when it has finished scrolling, and then 
    //firing a new scroll to the same position.

    //the bug is the case that sometimes smooth Scroll To Position sort of misses its intended position. 
    //more info here : https://code.google.com/p/android/issues/detail?id=36062
    listView.smoothScrollToPositionFromTop(position, offset, duration);
    listView.setOnScrollListener(new OnScrollListener() {

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if(scrollState==OnScrollListener.SCROLL_STATE_IDLE){
                listView.setOnScrollListener(null);
                listView.smoothScrollToPositionFromTop(position, offset, duration);
            }

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        }
    });
}
于 2013-04-05T08:14:49.733 に答える