2013-04-11 15 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(); 
    } 
} 

詳細フラグメントの1つの例。異なる状況で作成される可能性がある多くの異なるフラグメントがあります。電話で、ラッパー活性はフラグメントを保持するために使用される場合

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

この状況で、詳細ペインに開かれているフラグメントを変更する適切な方法は何ですか?私の方法は、2つのペインを使用するときのハックのように感じ、1つのペインを使用するときには機能しません。parent.changeDetailFragment()を呼び出せなくなるため、SinglePaneFragmentWrapperのgetParent()がnullを返すためです。

これは複雑な質問です。うまくいけばそれをうまく説明しました。私が何かを見逃したら私に知らせてください。ありがとう

答えて

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

と実装あなたの1つのペインの活動に対して同じインタフェース...

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

} 

注あなたの1つのペインとあなたのマルチペインの活動との間の類似性。これは、あなたがに重複コード(changefragmentなど)のすべてを置くことができるいずれかのことを示唆しています彼らが広がっている、あるいは異なるレイアウトの同じ活動であるかもしれない単一の活動...

私はそれが助けてくれることを祈っています。

よろしくお願いします。 CJ

関連する問題