42

我試圖平滑滾動到與listview關聯的arrayadapter元素後添加列表的最後一個元素。 的問題是,它只是滾動到一個隨機位置android:smoothScrollToPosition()不能正常工作

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

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

這種方法從來沒有爲我工作。 – 2012-07-11 14:31:07

+2

已知錯誤:請參閱回答https://stackoverflow.com/questions/14479078/smoothscrolltopositionfromtop-is-not-always-working-like-it-should/20997828#20997828 – 2014-08-22 14:00:23

回答

1

你叫arrayadapter.notifyDataSetChanged()你叫arrayadapter.add()後?另外可以肯定的是,如上所述,smoothScrollToPositionsetSelection是在ListView而非arrayadapter中可用的方法。

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

+0

是的..我在論壇上犯了一個錯誤,當然是listview.smoothScrollToPosition(pos)和listview.setSelection(pos)。 和notifyDataSetChanged在調用arrayadapter.add()..時被自動調用,否則setSelection不會工作 – user1515520 2012-07-11 12:34:39

+1

setSelection(pos)完美地工作,但smoothScrollToPosition(pos)不是這樣嗎? – user1515520 2012-07-11 12:41:02

5

您應該使用爲setSelection()方法。

+2

這不一定是一樣的,你可能不希望被選中的項目,或者你可以簡單地尋找平滑的效果 – mdelolmo 2012-11-06 11:27:05

+0

它實際上幫助我,而不是沒有發生,它仍然滾動到列表的最後。 – Slickelito 2012-12-05 14:57:17

+1

'setSelection'確實可以在'smoothScrollToPosition'沒有的地方起作用,但是如果你可以讓我們知道它爲什麼如此,那將會很有幫助。 – 2013-10-09 13:41:26

51

你可能想告訴ListView在UI線程可以處理它時發佈滾動(這就是爲什麼你不能正確滾動)。 SmoothScroll需要做很多工作,而不是僅僅忽略速度/時間等。 (需要「動畫」)。

因此,你應該這樣做:

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

+1爲'post'的想法。然而,我偶然發現了'smoothScrollToPosition'仍然不起作用的情況,在小部件頂部和位置中的項目之間留下一個小的偏移空間以滾動到。在這些情況下,'setSelection'(當然結合'post')完美地工作。 – 2013-10-09 13:39:51

+0

是的,我也是。 ListViews不如UITableView等。這很讓人傷心,因爲列表是屏幕大小受損的移動設備的核心概念,因此我們必須滾動顯示內容。無論如何,只要你知道,滾動工作,你只需要瞭解規則,佈局必須已經鋪好,你必須在UI線程中完成,你必須發佈它,以便列表可以排隊操作等。滾動發生必須發生很多魔術。我確信@RomanianGuy可以投入更多的光線。儘管如此,iSO的實施仍然完美無缺。 – 2013-10-09 18:59:44

+5

這傢伙的名字是@RomainGuy BTW。 – 2013-10-10 07:37:30

11

(從我的答案複製:smoothScrollToPositionFromTop() is not always working like it should

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

不過,我實現了這個解決方法與可能發生的所有邊緣案件涉及:

第一次調用smothScrollToPositionFromTop(position),然後當滾動完成,調用setSelection(position)。後者通過直接跳轉到所需的位置來糾正不完整的滾動。這樣做的用戶仍然有這樣的印象,即它正在被動畫滾動到這個位置。

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

smoothScrollToPosition()

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

這是正確的答案,謝謝! – FireZenk 2016-01-31 12:31:34

2

由拉斯工作提到的組選擇方法,但動畫對我們的目的來說太過分了因爲它會跳過剩下的東西。另一個解決方案是重複調用該方法,直到第一個可見位置是您的索引。這最好快速完成,並且有限制,否則將會與用戶滾動視圖相沖突。

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#via。 Xamarin,但應該很容易翻譯成Java。

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