2016-05-27 3 views
0

recyclerView.smoothScrollToPositionを呼び出すと予期しない動作が発生します。RecyclerView smoothScrollToPositionは、アクティビティレイアウトにレイアウトウェイトがあるか、CardViewがリニアレイアウト内にあるときに不正な位置にスクロールします。

十分なアイテムを追加して画面から外に出ると、2-3時間後に正しくスクロールして下にスクロールしません。そして、15を足した後、項目を追加すると位置0にスクロールし始め、次の項目は下にスクロールします。別のアイテムを追加すると0になり、もう一度やり直すと下に移動します。

あなたは何が起こっているのかを添付のビデオで見ることができます。スクロールバーにも注意してください。一度スクロールバーが画面から消え始めると、

imgurのGifですが、15秒に制限されています。 http://i.imgur.com/FnjsTY1.gifv]

全体のビデオはこちらです - https://www.dropbox.com/s/k6aaca5ue6lkk21/device-2016-05-27-130928.mp4?dl=0

私は突然、テストアプリで問題を解決する二つに絞られるまで、私は離れて私のアプリを引き裂きました。

私のアクティビティレイアウトはレイアウトウェイトを使用しており、それを削除すると再び正しくスクロールし始めます。さらに、recylerViewに表示されているCardViewには、余分なLinearLayoutがあります。それを削除することでも問題は解決します。

これらの解決策のどちらも私のアプリでは動作しませんおそらくこれらの2つのような問題があります。これはまた、バグを表示するために最小限の量にまで私を裂くことです、私のレイアウトははるかに複雑です。

なぜそれが間違っているのか完全にわからないので、私は何をすべきか分かりません。カスタムスクロールバーでカスタムリニアレイアウトマネージャを試しましたが、これは常に同じ問題です。以下

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> 

のGradle

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:reの代わりに23.1.1 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

ダウングレードする必要がある最初の提案は問題を解決します。私もgoogleでバグレポートを記録し、彼らはさらにこの問題を説明するhttps://code.google.com/p/android/issues/detail?id=203276に私に指摘しました。私はまた、リサイクル・ビューだけでなく、問題をやめさせるためにデザインライブラリを元に戻さなければなりませんでした。答えの第二部分全体は意味をなさない。私は毎回最後の位置を正しく設定していましたが、setHasFixedSizedは何も解決しません。私は私のケースではダウングレードが機能して以来、あなたに恩恵を与えていますが、根拠はありません。 – Ben987654

+0

2番目のオプションは意味があります。 recyclerviewに問題はありません。唯一のことは、 'adapter.notifyItemInserted()'を実行するたびに変更が発生し、recyclerviewが最初の位置に移動することです。これを確認するには、smoothScrollToPosition()の呼び出しを削除します。現在、recyclerView.setHasFixedSize(true)を使用しています。あなたの問題を解決する最初の位置にリサイクルビューが戻るのを防ぎます。私はなぜそれがあなたのために働いていないのかわかりませんが、あなたが提供したコードにそれを入れて、23.1.1にライブラリをダウングレードせずに私のために働いていました。 –

関連する問題