2013-04-11 87 views
5

我正在嘗試使用片段創建具有主/明細流的應用程序。選擇一個項目將打開一個細節片段,然後可以打開另一個片段並將其添加到後端堆棧。在主/細節流中切換片段

我已經重新命名了類來幫助說明他們做了什麼。

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(); 
    } 
} 

其中一個詳細片段的示例。在不同情況下可能會創建許多不同的片段。

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()); 
      } 
     }); 
    } 
} 

當電話,一個包裝活動是用來裝片段

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 { 
      ... 
     } 
    } 
} 

什麼是改變就是在這種情況下的細節窗格中打開該片段的正確方法?我的方法在使用兩個窗格時感覺像是黑客,並且在僅使用一個窗格時不起作用,因爲來自SinglePaneFragmentWrapper的getParent()返回null,使我無法呼叫parent.changeDetailFragment()

這是一個複雜的問題,希望我解釋得很好。讓我知道如果我錯過了什麼。謝謝

回答

1

有很多這方面的意見和很多方法來做到這一點。我認爲在這種情況下問題是「誰負責改變片段?」在表面上看起來,按鈕上的監聽器似乎是顯而易見的地方,但是片段不應該知道它託管的是什麼(其症狀是從getParent()中獲得不良結果,如null)。

在你的情況下,我會建議你在父級實現一個「偵聽器」接口,並從片段中「通知」..當通知父代時,它會更改片段。這樣的片段不改變本身(所以並不需要知道如何)..所以..你..案件

添加一個新的接口:

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

實現你的ListOfDetails接口活動

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); 
} 

} 

新增聽衆細節片段

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); 
     } 
    } 
} 

和落實同一接口的單窗格的活動......

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); 
} 

} 

注意您的單一窗口和你多窗格活動之間的相似性。這意味着你既可以把所有的重複代碼(changefragment等)成單個活動,他們都延伸或者可能他們是不同佈局的相同活動...

我希望有幫助,祝你好運。

Regards, CJ