簡體   English   中英

android:smoothScrollToPosition() 不能正常工作

[英]android: smoothScrollToPosition() not working correctly

在將元素添加到與列表視圖關聯的數組適配器后,我試圖平滑滾動到列表的最后一個元素。 問題是它只是滾動到一個隨機位置

arrayadapter.add(item);
//DOES NOT WORK CORRECTLY:
listview.smoothScrollToPosition(arrayadapter.getCount()-1);

//WORKS JUST FINE:
listview.setSelection(arrayadapter.getCount()-1);

您可能想要告訴 ListView 在 UI 線程可以處理它時發布滾動(這就是為什么它不能正確滾動)。 SmoothScroll 需要做很多工作,而不是僅僅去一個忽略速度/時間/等的位置。 (“動畫”所需)。

因此,您應該執行以下操作:

    getListView().post(new Runnable() {
        @Override
        public void run() {
            getListView().smoothScrollToPosition(pos);
        }
    });

(復制自我的回答: smoothScrollToPositionFromTop() 並不總是像它應該的那樣工作

這是一個已知的錯誤。 https://code.google.com/p/android/issues/detail?id=36062

但是,我實施了此解決方法來處理可能發生的所有邊緣情況:

首先調用smothScrollToPositionFromTop(position) ,然后在滾動完成后調用setSelection(position) 后一個調用通過直接跳轉到所需位置來糾正不完整的滾動。 這樣做,用戶仍然會覺得它正在被動畫滾動到這個位置。

我在兩個輔助方法中實現了這個解決方法:

平滑滾動到位置()

public static void smoothScrollToPosition(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;
    }
}

您應該使用 setSelection() 方法。

使用 LayoutManager 平滑滾動

layoutManager.smoothScrollToPosition(recyclerView, new RecyclerView.State(), position);

Lars 提到的設置選擇方法有效,但動畫對於我們的目的來說太跳躍了,因為它跳過了剩下的任何內容。 另一種解決方案是重復調用該方法,直到第一個可見位置是您的索引。 這最好快速完成並且有限制,否則它將對抗用戶滾動視圖。

private  void DeterminedScrollTo(Android.Widget.ListView listView, int index, int attempts = 0) {
    if (listView.FirstVisiblePosition != index && attempts < 10) {
        attempts++;
        listView.SmoothScrollToPositionFromTop (index, 1, 100);
        listView.PostDelayed (() => {
            DeterminedScrollTo (listView, index, attempts);
        }, 100);
    }
}

解決方案是在 C# 中通過。 Xamarin 但應該很容易轉換為 Java。

final Handler handler = new Handler();
//100ms wait to scroll to item after applying changes
handler.postDelayed(new Runnable() {
@Override
public void run() {
   listView.smoothScrollToPosition(selectedPosition);
}}, 100);

在調用arrayadapter.notifyDataSetChanged()之后是否調用了arrayadapter.add() 同樣可以肯定的是, smoothScrollToPositionsetSelectionListView可用的方法,而不是上面提到的arrayadapter

在任何情況下,看看這是否有幫助: smoothScrollToPosition after notifyDataSetChanged not working in android

在android java中使用它,它對我有用:

private void DeterminedScrollTo(int index, int attempts) {
        if (listView.getFirstVisiblePosition() != index && attempts < 10) {
            attempts++;
            if (listView.canScrollVertically(pos))
                listView.smoothScrollToPositionFromTop(index, 1, 200);
            int finalAttempts = attempts;
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    DeterminedScrollTo(index, finalAttempts);
                }
            }, 200);
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM