2017-07-17 67 views
0

我是Android開發的初學者。我試圖在LayoutManager上使用onSaveInstanceState()和onRestoreInstanceState()來保存RecyclerView的LayoutManager狀態(在經歷了很多StackOverflow問題之後),但我無法這樣做。我希望恢復RecyclerView旋轉時的滾動位置的設備。我也嘗試保存在佈局中使用的NestedScrollView的位置,但無法讓它工作。無法滾動到使用onSaveInstanceState()和onRestoreInstanceState()旋轉設備上的RecyclerView位置

片段類

public class RecipeDetailFragment extends Fragment { 

    private static final String BUNDLE_RECIPE_ID = "Recipe"; 
    private static final String BUNDLE_LAYOUT_MANAGER_KEY = "layout"; 
    public StepAdapter mStepAdapter; 
    public IngredientAdapter mIngredientAdapter; 
    private Recipe selectedRecipe; 
    private StepAdapter.StepAdapterOnClickHandler mClickHandler; 

    @BindView(R.id.rv_recipe_detail_steps) 
    RecyclerView mStepRecyclerView; 

    @BindView(R.id.rv_recipe_detail_ingredients) 
    RecyclerView mIngredientRecyclerView; 


    public RecipeDetailFragment() { 
    } 


    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 

     View rootView = inflater.inflate(R.layout.fragment_recipe_detail, container, false); 
     ButterKnife.bind(this, rootView); 

     mIngredientAdapter = new IngredientAdapter(); 
     mIngredientRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 
     mIngredientRecyclerView.setHasFixedSize(true); 
     mIngredientRecyclerView.setNestedScrollingEnabled(false); 

     mStepAdapter = new StepAdapter(getContext(), mClickHandler); 
     mStepRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 
     mStepRecyclerView.setHasFixedSize(true); 
     mStepRecyclerView.setNestedScrollingEnabled(false); 

     if (savedInstanceState != null) { 
      selectedRecipe = savedInstanceState.getParcelable(BUNDLE_RECIPE_ID); 
     } 
     mIngredientAdapter.setIngredientData(selectedRecipe.getIngredients()); 

     mStepAdapter.setStepData(selectedRecipe.getSteps()); 

     mIngredientRecyclerView.setAdapter(mIngredientAdapter); 

     mStepRecyclerView.setAdapter(mStepAdapter); 

     return rootView; 
    } 

    @Override 
    public void onViewStateRestored(@Nullable Bundle savedInstanceState) { 
     super.onViewStateRestored(savedInstanceState); 
     if (savedInstanceState != null) { 

      Parcelable state = savedInstanceState.getParcelable(BUNDLE_LAYOUT_MANAGER_KEY); 
      mStepRecyclerView.getLayoutManager().onRestoreInstanceState(state); 
     } 
    } 


    public void setRecipe(Recipe recipe) { 
     selectedRecipe = recipe; 
    } 

    @Override 
    public void onAttach(Context context) { 
     super.onAttach(context); 
     try { 
      mClickHandler = (StepAdapter.StepAdapterOnClickHandler) context; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     outState.putParcelable(BUNDLE_RECIPE_ID, selectedRecipe); 
     outState.putParcelable(BUNDLE_LAYOUT_MANAGER_KEY, mStepRecyclerView.getLayoutManager() 
       .onSaveInstanceState()); 

    } 
} 

佈局

<?xml version="1.0" encoding="utf-8"?> 

<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:id="@+id/recipe_detail_nested_scroll_view" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:focusable="true" 
    android:descendantFocusability="beforeDescendants" 
    android:fillViewport="true" 
    android:focusableInTouchMode="true"> 


    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:app="http://schemas.android.com/apk/res-auto" 
     android:id="@+id/ll_recipe_detail_scroll" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:descendantFocusability="beforeDescendants" 
     android:fillViewport="true" 
     android:focusableInTouchMode="true" 
     android:orientation="vertical"> 

     <android.support.v7.widget.CardView xmlns:cardView="http://schemas.android.com/apk/res-auto" 
      android:id="@+id/ingredients_card" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_marginBottom="8dp" 
      android:layout_marginLeft="12dp" 
      android:layout_marginRight="12dp" 
      android:layout_marginTop="8dp" 
      cardView:cardCornerRadius="4dp" 
      cardView:cardElevation="4dp"> 

      <LinearLayout 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:orientation="vertical"> 

       <TextView 
        android:id="@+id/tv_recipe_detail_ingredients_label" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_gravity="center" 
        android:padding="8dp" 
        android:text="@string/label_ingredients" 

        android:textAppearance="@style/Base.TextAppearance.AppCompat.Widget.ActionMode.Title" 
        android:textSize="28sp" /> 

       <android.support.v7.widget.RecyclerView xmlns:app="http://schemas.android.com/apk/res-auto" 
        android:id="@+id/rv_recipe_detail_ingredients" 
        android:layout_width="match_parent" 
        android:focusable="false" 
        android:layout_height="match_parent" 
        android:paddingBottom="8dp" /> 
      </LinearLayout> 
     </android.support.v7.widget.CardView> 

     <android.support.v7.widget.CardView xmlns:cardView="http://schemas.android.com/apk/res-auto" 
      android:id="@+id/steps_card" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_marginBottom="8dp" 
      android:layout_marginLeft="12dp" 
      android:layout_marginRight="12dp" 
      android:layout_marginTop="8dp" 
      cardView:cardCornerRadius="4dp" 
      cardView:cardElevation="4dp"> 

      <LinearLayout 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:orientation="vertical"> 

       <TextView 
        android:id="@+id/tv_recipe_detail_steps_label" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_gravity="center" 
        android:padding="8dp" 
        android:paddingBottom="16dp" 
        android:text="@string/label_steps" 
        android:textAppearance="@style/Base.TextAppearance.AppCompat.Widget.ActionMode.Title" 
        android:textSize="28sp" /> 

       <android.support.v7.widget.RecyclerView 
        android:id="@+id/rv_recipe_detail_steps" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:focusable="false" 
        android:paddingBottom="16dp" /> 
      </LinearLayout> 
     </android.support.v7.widget.CardView> 
    </LinearLayout> 
</android.support.v4.widget.NestedScrollView> 

P.S.這是我第一次在這裏發佈問題,所以如果我沒有正確發佈問題,請讓我知道!

+0

上保存實例的狀態,你嘗試過'mStepRecyclerView.getAdapterPosition( )'? –

+0

是的。不知何故工作。當我嘗試使用onCreateView()中的適配器位置檢索視圖時,它返回了一個空視圖 –

回答

0

與您使用片段確保你沒有做片段交易時savedInstanceState不承載片段上旋轉活動活動null被重新 首先你需要保存的數據傳遞到適配器中savedInstanceState如果savedInstanceState不是null使用這些數據

,並使用該自定義recyclerview

package eu.f3rog.ui.custom; 
 

 
import android.content.Context; 
 
import android.os.Bundle; 
 
import android.os.Parcelable; 
 
import android.support.annotation.Nullable; 
 
import android.support.v7.widget.RecyclerView; 
 
import android.util.AttributeSet; 
 

 
/** 
 
* Class {@link StatefulRecyclerView} extends {@link RecyclerView} and adds position management on configuration changes. 
 
* 
 
* @author FrantisekGazo 
 
* @version 2016-03-15 
 
*/ 
 
public final class StatefulRecyclerView 
 
     extends RecyclerView { 
 

 
    private static final String SAVED_SUPER_STATE = "super-state"; 
 
    private static final String SAVED_LAYOUT_MANAGER = "layout-manager-state"; 
 

 
    private Parcelable mLayoutManagerSavedState; 
 

 
    public StatefulRecyclerView(Context context) { 
 
     super(context); 
 
    } 
 

 
    public StatefulRecyclerView(Context context, @Nullable AttributeSet attrs) { 
 
     super(context, attrs); 
 
    } 
 

 
    public StatefulRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { 
 
     super(context, attrs, defStyle); 
 
    } 
 

 
    @Override 
 
    protected Parcelable onSaveInstanceState() { 
 
     Bundle bundle = new Bundle(); 
 
     bundle.putParcelable(SAVED_SUPER_STATE, super.onSaveInstanceState()); 
 
     bundle.putParcelable(SAVED_LAYOUT_MANAGER, this.getLayoutManager().onSaveInstanceState()); 
 
     return bundle; 
 
    } 
 

 
    @Override 
 
    protected void onRestoreInstanceState(Parcelable state) { 
 
     if (state instanceof Bundle) { 
 
      Bundle bundle = (Bundle) state; 
 
      mLayoutManagerSavedState = bundle.getParcelable(SAVED_LAYOUT_MANAGER); 
 
      state = bundle.getParcelable(SAVED_SUPER_STATE); 
 
     } 
 
     super.onRestoreInstanceState(state); 
 
    } 
 

 
    /** 
 
    * Restores scroll position after configuration change. 
 
    * <p> 
 
    * <b>NOTE:</b> Must be called after adapter has been set. 
 
    */ 
 
    private void restorePosition() { 
 
     if (mLayoutManagerSavedState != null) { 
 
      this.getLayoutManager().onRestoreInstanceState(mLayoutManagerSavedState); 
 
      mLayoutManagerSavedState = null; 
 
     } 
 
    } 
 

 
    @Override 
 
    public void setAdapter(Adapter adapter) { 
 
     super.setAdapter(adapter); 
 
     restorePosition(); 
 
    } 
 
}

+0

謝謝!我沒有檢查我的片段是否被創建兩次,因爲我沒有檢查savedInstanceState的值。將事務的開始放在if(savedInstanceState == null)中解決它!謝謝! –

0

只要您的RecyclerView設置了id,您在旋轉設備時就不必執行任何操作來保存其滾動狀態。這是一個非常簡單的應用程序,演示這一點。

MainActivity.java:

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     RecyclerView recycler = (RecyclerView) findViewById(R.id.recycler); 
     recycler.setAdapter(new MyAdapter()); 
    } 

    private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { 

     @Override 
     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
      LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
      View itemView = inflater.inflate(R.layout.itemview, parent, false); 
      return new MyViewHolder(itemView); 
     } 

     @Override 
     public void onBindViewHolder(MyViewHolder holder, int position) { 
      holder.text.setText("" + position); 
     } 

     @Override 
     public int getItemCount() { 
      return 100; 
     } 
    } 

    private static class MyViewHolder extends RecyclerView.ViewHolder { 

     private final TextView text; 

     public MyViewHolder(View itemView) { 
      super(itemView); 
      this.text = (TextView) itemView.findViewById(R.id.text); 
     } 
    } 
} 

activity_main.xml中:

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

itemview.xml:

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:padding="8dp" 
    android:gravity="center_vertical" 
    android:orientation="horizontal"> 

    <ImageView 
     android:layout_width="48dp" 
     android:layout_height="48dp" 
     android:src="@drawable/ic_android_black_24dp"/> 

    <TextView 
     android:id="@+id/text" 
     android:layout_width="0dp" 
     android:layout_height="wrap_content" 
     android:layout_weight="1" 
     android:layout_marginLeft="12dp" 
     android:layout_marginStart="12dp" 
     android:textSize="14sp" 
     tools:text="Hello world"/> 

</LinearLayout> 
+0

這並沒有真正幫助我。我使用RecyclerView作爲CardView的子視圖,該視圖本身是佈局的子視圖。我已經爲RecyclerView設置了一個ID,但它不能恢復滾動狀態 –

+0

您的recyclerview適配器中的數據是如何填充的?如果數據在回收者查看恢復其位置時不存在,系統的自動恢復功能將不起作用。 –

+0

我存儲了onSaveInstanceState()所需的數據,然後將其傳遞給使用它填充RecyclerView的適配器 –

相關問題