2016-07-22 90 views
1

今天我有一個很奇怪的問題:我有一個RecyclerView,水平顯示一些縮略圖,我用smoothScrollToPosition導航到我需要的項目,但我注意到一個問題:它會不滾動到最後一個項目。經過進一步的調試,我發現我的回收站的兒童數量比顯示的少!我看到五個項目,每次顯示三個項目。但兒童數(得到recyclerView.getChildCount)返回4而不是5,我不能得到getChildAt(4)最後一個孩子。更怪,adapter.getItemCount()回報5,和recyclerView.getAdapter().getItemCount()回報5 ...RecyclerView兒童數量少於兒童人數

在檢查,recyclerView.getLayoutManager().getItemCount()回報5,和'recyclerView..getLayoutManager()。getChildCount()返回4 ...

我需要兩件東西:首先,我需要我的recyclerView滾動到最後一個項目,第二:我需要能夠獲取所有孩子,因爲我在用戶與項目進行交互時對其進行了一些修改。

一些代碼:

// Scrolling and editing the item inside the recyclerView 
// It doesn't scroll to position 4, even having a item there... 
mLayoutManager.smoothScrollToPosition(recyclerView, null, position); 

// the code bellow returns null if position = 4, even if the recyclerView adapter has a item at index 4, and it is visible... 
ImageView iv = (ImageView) recyclerView.getChildAt(position); 
if (iv != null) { 
    iv.setPadding(10, 10, 10, 10); 
    iv.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark)); 
    ImageView ivo = (ImageView) recyclerView.getChildAt(position - 1); 
    if (position - 1 == 0) { 
     ivo.setPadding(10, 10, 10, 10); 
    } else { 
     ivo.setPadding(0, 10, 10, 10); 
    } 
    ivo.setBackgroundColor(getResources().getColor(R.color.transparent)); 
} 

smoothScrollToPosition實現:

public class SnappingLinearLayoutManager extends LinearLayoutManager { 

    private static final float MILLISECONDS_PER_INCH = 150f; 

    public SnappingLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 
     super(context, orientation, reverseLayout); 
    } 

    @Override 
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 
             int position) { 
     RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext()){ 
      @Override 
      public PointF computeScrollVectorForPosition(int targetPosition) { 
       return new PointF(0, 1); 
      } 

      //This returns the milliseconds it takes to scroll one pixel. 
      @Override 
      protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 
       return MILLISECONDS_PER_INCH/displayMetrics.densityDpi; 
      } 
     }; 
     smoothScroller.setTargetPosition(position); 
     startSmoothScroll(smoothScroller); 
    } 

    private class TopSnappedSmoothScroller extends LinearSmoothScroller { 
     public TopSnappedSmoothScroller(Context context) { 
      super(context); 

     } 

     @Override 
     public PointF computeScrollVectorForPosition(int targetPosition) { 
      return SnappingLinearLayoutManager.this 
        .computeScrollVectorForPosition(targetPosition); 
     } 

     @Override 
     protected int getVerticalSnapPreference() { 
      return SNAP_TO_ANY; 
     } 
    } 
} 
+2

RecycleView不包含適配器中的所有項目。它只能顯示視圖的視圖+在回收站視圖列表的開始和結尾處有一些額外的視圖,因此它可以使其更快。也許這是問題所在。 – Rafal

回答

1

1)滾動到列表中的一個位置,你可以使用scrollToPosition(position)。你傳遞的位置將是最後一個項目像這樣的指標:

recyclerView.smoothScrollToPosition(adapter.getItemCount()) 

我能夠得到這種方法與V7 RecyclerView和Android的LinearLayoutManager工作。

的build.gradle

... 
dependencies { 
    ... 
    compile 'com.android.support:appcompat-v7:23.4.0' 
    compile 'com.android.support:recyclerview-v7:23.4.0' 
    ... 
} 

RecyclerView佈局代碼:

<android.support.v7.widget.RecyclerView android:id="@+id/item_list" 
    android:name="fbalashov.spikeapp.ItemListFragment" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    app:layoutManager="LinearLayoutManager" /> 

然後,當我想滾動到列表頂部我剛剛打電話給我scrollToBottom方法:

private void scrollToBottom() { 
    recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount()); 
} 

這會使RecyclerView平滑滾動到列表中的最後一個項目。

2)Rafal聲明,RecyclerView(和ListView)只繪製屏幕上可見的項目+上面和下面的一個項目或兩個緩衝區,使滾動看起來不錯。在您滾動時,它將「回收」視圖並使用適配器中的數據填充視圖。因此,從頂部滾動的視圖將在列表底部重新使用,數據形成下一個項目。

因此,您無法同時獲取適配器中所有項目的所有視圖。但是,您可以獲取適配器中的所有項目,對其進行修改,然後使用adapter.notifyDataSetChanged()觸發適配器重新繪製recyclerView中的視圖。例如:

// getItems() is a method you will have to add to you adapter to get the items from your 
// adapter. Otherwise you can add a method in your adapter to update the items. 
List<DataType> items = adapter.getItems(); 
for (DataType item : items) { 
    // make some change to each item 
} 
// this will force the recycler view to redraw its views 
adapter.notifyDataSetChanged(); 

您還可以通過只是在適配器更新這些項目,並使用notifyItemChanged(position)使在適配器項目更有針對性的變化。

+0

謝謝Nitpick博士!我沒有使用'scrollToPosition',因爲它沒有動畫,其他帖子建議我應該使用'smoothScrollToPosition'來製作動畫卷軸......你能指點更新還是指向我可以學習如何獲得一個位置的位置帶有'scrollToPosition'的動畫滾動?關於計數,感謝您的建議,我會嘗試以某種方式標記視圖,以便根據需要編輯它們... –

+0

您是否使用[RecyclerView from support v7](https://developer.android.com/話題/庫/支持庫/#的features.html V7-recyclerview)?我能夠將它與android的LinearLayoutManager一起使用,以實現平滑滾動到列表的底部,而無需重寫'smoothScrollToPosition'。我將示例代碼添加到我的答案中。 –