2013-04-11 50 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