2013-04-11 13 views
5

Próbuję utworzyć aplikację z przepływem wzorcowym/szczegółowym przy użyciu fragmentów. Wybranie przedmiotu spowoduje otwarcie fragmentu szczegółów, który może następnie "otworzyć" inny fragment i dodać go do tylnego stosu.Przełączanie fragmentów w przepływie nadrzędnym/szczegółowym

Zmieniłem nazwy klas, aby pomóc zilustrować, co robią.

public class ListOfDetails extends FragmentActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     ... 
    } 

    //Callback method indicating that an item with the given ID was selected. 
    public void onItemSelected(String id) { 
     // Performing logic to determine what fragment to start omitted 

     if (ifTwoPanes()) { 
      Fragment fragment = new DetailFragmentType1(); 
      getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit(); 
     } else { 
      Intent newIntent = new Intent(this, SinglePaneFragmentWrapper.class); 
      newIntent.putExtra("id", id); 
      startActivity(newIntent); 
     } 
    } 

    // My attempt at making it possible to change displayed fragment from within fragments 
    public void changeDetailFragment(Fragment fragment) { 
     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
     transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
     transaction.addToBackStack(null); 
     transaction.replace(R.id.aContainer, fragment); 
     transaction.commit(); 
    } 
} 

Przykład jednego z fragmentów szczegółów. Istnieje wiele różnych Fragmentów, które mogą być tworzone w różnych okolicznościach.

public class DetailFragmentType1 extends Fragment { 
    private ListOfDetails parent; 

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

     Activity a = getActivity(); 
     if (a instanceof ListOfDetails) { 
      parent = (ListOfDetails) a; 
     } 
    } 

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

     Button aButton = (Button) getActivity().findViewById(R.id.aButton); 
     aButton.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       parent.changeDetailFragment(new SubDetailFragment()); 
      } 
     }); 
    } 
} 

Gdy na telefonie, działalność owinięcie jest używana do przechowywania fragmentu

public class SinglePaneFragmentWrapper extends FragmentActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // Duplicate logic must be performed to start fragment 
     // Performing logic to determine what fragment to start omitted 
     String id = getIntent().getStringExtra("id"); 
     if(id == "DetailFragmentType1") { 
      Fragment fragment = new DetailFragmentType1(); 
      getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit(); 
     } else { 
      ... 
     } 
    } 
} 

Jaki jest właściwy sposób zmienić fragment, który jest otwarty w okienku szczegółów w tej sytuacji? Moja metoda wygląda jak włamanie przy użyciu dwóch paneli i nie działa nawet przy użyciu tylko jednego panelu, ponieważ getParent() z SinglePaneFragmentWrapper zwraca null, co uniemożliwia wywołanie parent.changeDetailFragment().

To skomplikowane pytanie, mam nadzieję, że wyjaśniłem to dobrze. Daj mi znać, jeśli coś przeoczyłem. Dzięki

Odpowiedz

1

Istnieje wiele opinii na ten temat i wiele sposobów na zrobienie tego. Myślę, że w tym przypadku problemem jest "kto jest odpowiedzialny za zmianę fragmentu?" na pozór wydaje się, że słuchacz na przycisku jest oczywistym miejscem, ale wtedy fragment nie powinien wiedzieć, w czym jest hostowany (objawem tego jest uzyskanie niepożądanego wyniku, jak null z getParent()).

W twoim przypadku sugerowałbym implementację interfejsu "detektora" w rodzicu i "powiadomienie" z fragmentu. Gdy rodzic jest powiadomiony, zmienia fragment. W ten sposób fragment nie zmienia się (więc nie trzeba wiedzieć jak) .. tak .. w Twoim przypadku ..

Dodaj nowy interfejs:

public interface FragmentChangeListener { 
    void onFragmentChangeRequested(Fragment newFragment); 
} 

implementować interfejs w swoim ListOfDetails aktywność

public class ListOfDetails extends FragmentActivity implements FragmentChangeListener { 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    ... 
} 

//Callback method indicating that an item with the given ID was selected. 
public void onItemSelected(String id) { 
    // Performing logic to determine what fragment to start omitted 

    if (ifTwoPanes()) { 
     Fragment fragment = new DetailFragmentType1(); 
     getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit(); 
    } else { 
     Intent newIntent = new Intent(this, SinglePaneFragmentWrapper.class); 
     newIntent.putExtra("id", id); 
     startActivity(newIntent); 
    } 
} 

// My attempt at making it possible to change displayed fragment from within fragments 
public void changeDetailFragment(Fragment fragment) { 
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
    transaction.addToBackStack(null); 
    transaction.replace(R.id.aContainer, fragment); 
    transaction.commit(); 
} 

// This is the interface implementation that will be called by your fragments 
void onFragmentChangeRequested(Fragment newFragment) { 
    changeDetailFragment(newFragment); 
} 

} 

Dodany słuchaczowi szczegół fragmentu

public class DetailFragmentType1 extends Fragment { 

    private FragmentChangeListener fragmentChangeListener; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // Actually you might not have an activity here.. you should probably be 
     // doing this in onAttach 
     //Activity a = getActivity(); 
     //if (a instanceof ListOfDetails) { 
     // parent = (ListOfDetails) a; 
     //} 
    } 

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

     Button aButton = (Button) getActivity().findViewById(R.id.aButton); 
     aButton.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       // parent.changeDetailFragment(new SubDetailFragment()); 
       notifyFragmentChange(new SubDetailFragment()); 
      } 
     }); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     // This is called when the fragment is attached to an activity.. 
     if (activity instanceof FragmentChangeListener) { 
      fragmentChangeListener = (FragmentChangeListener) activity; 
     } else { 
     // Find your bugs early by making them clear when you can... 
     if (BuildConfig.DEBUG) { 
      throw new IllegalArgumentException("Fragment hosts must implement FragmentChangeListener"); 
     } 
     } 
    } 

    private void notifyFragmentChange(Fragment newFragment) { 
     FragmentChangeListener listener = fragmentChangeListener; 
     if (listener != null) { 
     listener.onFragmentChangeRequested(newFragment); 
     } 
    } 
} 

i wdrożenia sam interfejs do swojej aktywności pojedynczego okienka ...

public class SinglePaneFragmentWrapper extends FragmentActivity implements FragmentChangeListener { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // Duplicate logic must be performed to start fragment 
     // Performing logic to determine what fragment to start omitted 
     String id = getIntent().getStringExtra("id"); 
     if(id == "DetailFragmentType1") { 
      Fragment fragment = new DetailFragmentType1(); 
      getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit(); 
     } else { 
      ... 
     } 
    } 
// My attempt at making it possible to change displayed fragment from within fragments 
public void changeDetailFragment(Fragment fragment) { 
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
    transaction.addToBackStack(null); 
    transaction.replace(R.id.aContainer, fragment); 
    transaction.commit(); 
} 

// This is the interface implementation that will be called by your fragments 
void onFragmentChangeRequested(Fragment newFragment) { 
    changeDetailFragment(newFragment); 
} 

} 

Uwaga podobieństwa między pojedynczym swoich działań zespolonych szyby i .. to sugeruje, że można też umieścić wszystkie skopiowanego kodu (changefragment etc) do pojedyncza aktywność, którą obaj rozszerzają lub, że być może są to te same czynności o różnych układach ...

Mam nadzieję, że to pomoże, powodzenia.

Pozdrawiam, CJ

Powiązane problemy