RecyclerView滾動指定條目并在頁面中居中
内容提要
本次的需求是通過指定position來控制條目滾動,并且要滾動到指定到中間的位置。
下面先上圖,看看是不是你要

如下介紹主要的步驟
帶着問題去做需求是一個很不錯的方式:
1.我們要滾動條目?怎麼滾動呢?
2.滾動到指定的position是很容易,但是條目并沒有到指定準确的位置,怎麼辦呢?
上面的兩個問題解決了,我們的需求就完成了。
下面先解決第一個問題
這個很簡單了,我就一筆帶過好了啊。
recyclerView.scrollToPosition(trim);
你沒看錯就是這個方法。(手動滑稽)
然後是第二個問題
上圖中的标号請無視。
這裡要計算了,首先我們要先确定條目的位置,其次是将該條目移動到中間的位置。
将條目1,移動到箭頭所在位置。
view1.getX();擷取view1的x坐标(黃色到第一個藍色的距離),擷取view的寬度的一半(藍色到綠色的距離),然後在擷取外層view的寬度(我這是直接填充的螢幕寬度,黃色到第二個藍色的距離),然後計算出view1需要移動的x距離。如下:
recyclerView.smoothScrollBy(changeX - (width - childWidth), );
計算看着比較簡單,但是實際卻需要做很多限制。以下注意事項:
1.首先RecyclerView的條目是要複用的,是以實際的view數目是螢幕上顯示的,再多緩存一個或者兩個view(可以通過getChildCount()方法擷取數量),是以計算RecyclerView條目的時候要注意不要取到螢幕外的view,會造成空指針。
2.其次就是要注意position是否大于了緩存的view數目,如果大于我們就取最大的view角标;并且我們還要區分前後滾動,因為如果大于緩存的view數向後滾動就是就是取最大的view角标,如果小于緩存的view數向後滾動的話就直接取position作為角标的view了。
上面寫的有點難懂,下面直接上代碼,
if (trim > recyclerView.getChildCount() - ) {
if (oldInt > trim) {
childAt = recyclerView.getChildAt();
} else {
childAt = recyclerView.getChildAt(recyclerView.getChildCount() - );
}
} else {
if (oldInt > trim) {
childAt = recyclerView.getChildAt();
} else {
childAt = recyclerView.getChildAt(trim);
}
}
結合代碼看會比較容易。
遺留的問題
基本上處理好上面兩個問題就可以達到我們的需求了,但是這裡還有一個遺留的問題,就是關于界面顯示的view數目和RecycledViewPool中view數目的關系。這裡我是實驗發現一般都會緩存一個view。是以在上面調用getChildAt()減去了1的,防止越界出現擷取到空view的情況。
放出關鍵的代碼部分,如果需要可以去文末下載下傳demo
final int width = rect.right / ;
//角标數,不能大于頁面最大的數目
final Integer trim = Integer.parseInt(ed.getText().toString().trim());
recyclerView.scrollToPosition(trim);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (trim > recyclerView.getChildCount() - ) {
if (oldInt > trim) {
childAt = recyclerView.getChildAt();
} else {
childAt = recyclerView.getChildAt(recyclerView.getChildCount() - );
}
} else {
if (oldInt > trim) {
childAt = recyclerView.getChildAt();
} else {
childAt = recyclerView.getChildAt(trim);
}
}
changeX = (int) childAt.getX();
childWidth = childAt.getMeasuredWidth() / ;
Log.d("x", changeX + "--" + recyclerView.getChildCount());
recyclerView.smoothScrollBy(changeX - (width - childWidth), );
}
}, );
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
oldInt = trim;
}
}, );
finish
雖然需求看着很簡單,但是涉及到的知識點還是很好,應該了解一下。
下載下傳demo點這裡