2016-05-27 58 views
0

當我打電話給recyclerView.smoothScrollToPosition時,出現意外的行爲。當活動佈局具有佈局權重或CardView位於線性佈局內時,RecyclerView smoothScrollToPosition會滾動到不正確的位置

當我添加足夠的物品並開始離開屏幕時,它不會正確地滾動到底部,保持2-3落後。然後,在添加15個左右後,當我添加一個項目時,它開始滾動到位置0,然後下一個項目滾動到底部。添加另一個項目,它將變爲0,然後再次移至底部。

你可以在附件中看到發生了什麼事。一旦它開始離開屏幕,請注意滾動條。

gif on imgur,但限於15秒。 http://i.imgur.com/FnjsTY1.gifv]

整個視頻可以在這裏找到 - https://www.dropbox.com/s/k6aaca5ue6lkk21/device-2016-05-27-130928.mp4?dl=0

我掰開我的應用程序,直到我把範圍縮小到兩件事情突然修復一個測試應用程序的問題。

我的活動佈局使用佈局權重,當我刪除它時,它開始再次正確滾動。此外,我在recylerView中顯示的CardView在其周圍還有一個額外的LinearLayout。刪除也解決了這個問題。

這些解決方案都不能在我的應用中工作,因爲這兩個問題可能會有更多的「疑難問題」問題。這也是我把它縮小到顯示錯誤的最小數量,我的佈局要複雜得多。

我不知道該怎麼做,因爲我甚至不完全確定它爲什麼是錯的。我試過自定義滾動條的自定義線性佈局管理器,它總是同樣的問題。

下面是用於與RecyclerView

public class MyFragment extends android.support.v4.app.Fragment { 

    RecyclerView recyclerView; 
    RecyclerAdapter adapter; 
    ViewGroup rootView; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     rootView = (ViewGroup) inflater.inflate(R.layout.fragmentlayout, container, false); 

     LinearLayoutManager llm = new LinearLayoutManager(getActivity()); 

     recyclerView = (RecyclerView) rootView.findViewById(R.id.inventory_recycler); 
     recyclerView.setLayoutManager(llm); 
     adapter = new RecyclerAdapter(new ArrayList<RecyclerItem>()); 
     recyclerView.setAdapter(adapter); 

     Button button = (Button) rootView.findViewById(R.id.button); 
     button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       addItem(); 
      } 
     }); 

     return rootView; 
    } 

    public void addItem(){ 
     adapter.getList().add(new RecyclerItem()); 
     adapter.notifyItemAdded(adapter.getList().size()-1); 
     recyclerView.smoothScrollToPosition(adapter.getList().size()-1); 
    } 

    public class RecyclerItem { 
     public RecyclerItem(){ 
     } 
    } 

    public static class RecyclerViewHolder extends RecyclerView.ViewHolder { 
     TextView name; 
     public RecyclerViewHolder(View v) { 
      super(v); 
      name = (TextView) v.findViewById(R.id.name); 
     } 
    } 

    public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerViewHolder> { 

     private final List<RecyclerItem> items; 

     public RecyclerAdapter(List<RecyclerItem> items) { 
      this.items = items; 
     } 

     @Override 
     public int getItemCount() { 
      return items.size(); 
     } 

     @Override 
     public void onBindViewHolder(final RecyclerViewHolder viewHolder, final int position) { 
      viewHolder.name.setText("" + position); 
     } 

     public List<RecyclerItem> getList() { 
      return items; 
     } 

     public void notifyItemAdded(int position) { 
      notifyItemInserted(position); 
     } 

     @Override 
     public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { 
      View itemView = LayoutInflater. 
        from(viewGroup.getContext()). 
        inflate(R.layout.card, viewGroup, false); 

      return new RecyclerViewHolder(itemView); 
     } 
    } 
} 

活動佈局(卸下佈局重量和設定值求解,以重新創建該問題

MainActivity

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     MyFragment fragment = new MyFragment(); 
     getSupportFragmentManager().beginTransaction() 
       .add(R.id.fragment_container, fragment).commit(); 
    } 
} 

MyFragment代碼問題)

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="match_parent" 
    android:orientation="horizontal"> 

     <FrameLayout 
      android:id="@+id/fragment_container" 
      android:layout_width="0dp" 
      android:layout_weight="1" 
      android:layout_height="fill_parent"/> 

</LinearLayout> 

片段佈局

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <Button 
     android:id="@+id/button" 
     android:layout_width="100dp" 
     android:layout_height="50dp" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:text="add item" /> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/inventory_recycler" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:layout_below="@id/button" 
     android:scrollbars="vertical" /> 

</RelativeLayout> 

卡布局(刪除多餘的LinearLayout解決問題)

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:card_view="http://schemas.android.com/apk/res-auto" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:orientation="vertical"> 

    <android.support.v7.widget.CardView 
     android:id="@+id/card_view" 
     android:layout_width="fill_parent" 
     android:layout_height="140dp" 
     android:layout_margin="4dp" 
     app:elevation="3dp" 
     card_view:cardCornerRadius="2dp"> 

     <TextView 
      android:id="@+id/name" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" /> 

    </android.support.v7.widget.CardView> 

</LinearLayout> 

搖籃

apply plugin: 'com.android.application' 

android { 
    compileSdkVersion 23 
    buildToolsVersion "23.0.2" 

    defaultConfig { 
     applicationId "com.sample.recyclertest" 
     minSdkVersion 16 
     targetSdkVersion 23 
     versionCode 1 
     versionName "1.0" 
    } 
    buildTypes { 
     release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     } 
    } 
} 

dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    compile 'com.android.support:appcompat-v7:23.4.0' 
    compile 'com.android.support:support-v4:23.4.0' 
    compile 'com.android.support:cardview-v7:23.4.0' 
    compile 'com.android.support:recyclerview-v7:23.4.0' 
} 
+0

附加信息 - 如果該位置已經在列表中,則平滑滾動至該位置。添加延遲的帖子以平滑滾動到新添加的項目不起作用。 – Ben987654

回答

4

一個直接的解決方案要做到這一點是使用recyclerview-v7:23.1.1而不是re cyclerview-V7:23.4.0。

另一種解決方案就是採用這種方法

/** 
    * RecyclerView can perform several optimizations if it can know in advance that RecyclerView's 
    * size is not affected by the adapter contents. RecyclerView can still change its size based 
    * on other factors (e.g. its parent's size) but this size calculation cannot depend on the 
    * size of its children or contents of its adapter (except the number of items in the adapter). 
    * <p> 
    * If your use of RecyclerView falls into this category, set this to {@code true}. It will allow 
    * RecyclerView to avoid invalidating the whole layout when its adapter contents change. 
    * 
    * @param hasFixedSize true if adapter changes cannot affect the size of the RecyclerView. 
    */ 
    public void setHasFixedSize(boolean hasFixedSize) 

recyclerView.setHasFixedSize(true);應該解決您的問題。 for 23.4.0

您的代碼存在的問題是,無論何時調用notifyItemInserted(),整個recyclerview都會再次被繪製,這會將您的recyclerview移動到第一個位置。最重要的是,你打電話recyclerView.smoothScrollToPosition(adapter.getList().size() - 1);,這意味着視圖會在頂部以及同時滾動到最後一個位置。這就是爲什麼它不會處於最底部的位置。所以只需撥打recyclerView.setHasFixedSize(true);以防止重繪。

+0

您必須降級的第一個建議才能解決問題。我還使用谷歌登錄了一個錯誤報告,他們向我指出了這個https://code.google.com/p/android/issues/detail?id=203276,它進一步解釋了這個問題。我也必須恢復設計庫,儘管要停止問題,而不僅僅是回收查看器。答案的整個第二部分雖然沒有意義。我每次都正確設置了最後一個位置,並且setHasFixedSized不能解決任何問題。因爲在我的情況下,降級是有效的,所以我會給你賞金,但是沒有理由。 – Ben987654

+0

第二種選擇是有道理的。請參閱recyclerview沒有問題。唯一的事情是,只要你做'adapter.notifyItemInserted()',就會發生變化,並且recyclerview移到第一個位置。您可以通過刪除對smoothScrollToPosition()的調用來驗證此情況;現在使用recyclerView.setHasFixedSize(true);將阻止recyclerview回到解決您的問題的第一個位置。我不知道它爲什麼不適合你,但是我把它放在你提供的代碼中,它對我沒有影響,但是沒有將庫降級到23.1.1。 –