11

バックプレス後にナビゲーションドロワーの選択状態を処理する適切な方法は何ですか?バックプレス後のナビゲーションドロワーの選択状態の更新

AndroidスタジオのSDKサンプルのように、n個のエントリを持つナビゲーションドロワーが(リストビュー内に)あります。 ナビゲーション・ドロワーの項目をクリックすると、それらをバック・スタックに追加したいので、私は戻ってそれらに移動できます。

私は引き出しの2番目のエントリで私をクリックすると

 FragmentManager fragmentManager = getSupportFragmentManager(); 
     FragmentTransaction transaction = fragmentManager.beginTransaction(); 
     if (position == 0) { 
      transaction.replace(R.id.container, new FragmentA()); 
     } else if (position == 1) { 
      transaction.replace(R.id.container, new FragmentB()); 
     } else { 
      transaction.replace(R.id.container, new FragmentC()); 
     } 
     transaction.addToBackStack(null); 
     transaction.commit(); 

、Bが選択されますしていると私はその後、バックボタンをクリックした場合A.を置き換え、フラグメントAが再び示されonNavigationDrawerItemSelected(int型POS)で

それはすべきだが、ナビゲーション・ドロワーではまだBが選択されている。

戻るを押した後にドロワの選択ステータスを更新するにはどうすればよいですか?

何とかmDrawerListView.setItemChecked(position、true)を呼び出す必要があります。またはNavigationDrawerFragment.selectItem(int position)です。しかし、どのポジションに?どのように私はそれを思い出すのですか?

onBackPressedでの代行受信?

@Override 
    public void onBackPressed() {} 

しかし、どのフラグメントが再びアクティブになっているかはどのようにわかりますか?そして、どのポジションに対応しているのか。

私には見えない簡単な解決策がありますか?ナビゲーション・ドロワと組み合わせてバックを使用し、選択状態を更新することが標準的なパターンであると思われる。

答えて

7

このパターンについては、「正しい後方ナビゲーション」ドキュメントのImplement Back Navigation for Fragmentsセクションに記載されています。

アプリケーションは、このようなアクションバーとして、あなたの破片の 現在の状態を反映するために、他のユーザーインターフェイス要素を更新した場合は、トランザクションのコミット時にUIを更新するために を覚えています。 トランザクションをコミットするときだけでなく、バ​​ックスタックが変更された後で、ユーザーインターフェイスの を更新する必要があります。 あなたが FragmentTransactionFragmentManager.OnBackStackChangedListenerを設定することで元に戻されたときのために聞くことができます:ナビゲーション引き出しの中に現在のオプションをリフレッシュするための適切な場所でしょう

getSupportFragmentManager().addOnBackStackChangedListener(
    new FragmentManager.OnBackStackChangedListener() { 
     public void onBackStackChanged() { 
      // Update your UI here. 
     } 
    }); 

+0

これは、更新するときにのみ質問に答えます。私はonBackPressed()を使うこともできます。主な問題は、引き出し内のどの位置を強調表示するかです。私はおそらく古い、今は "アクティブな"フラグメントとonNavigationDrawerItemSelectedのそれと逆のマッピングフラグメント - >位置を取得する必要があります。おそらく、setTargetFragmentで要求コードとしての位置を格納していますか? – spatialist

+1

@spatialistはい、それはうまくいくでしょうし、Fragmentの 'onCreateView()'でドロワに通知します。それにもかかわらず、私はまだonBackPressed()の代わりにリスナーを使うことを提案します。例えば、「戻る」を押すことによって、現在のフラグメントを実際に変更することはできない(例えば、検索ビューを閉じる)。 – matiash

4

私はこの問題の解決方法を見つけようとしていましたが、使用し終わった解決策は私の意見では「いい」ものではありませんでした。

私のアプリケーションでは、バックグラウンドにフラグメントを追加すると、ナビゲーションドロワーのフラグメント位置が追加されました。この方法で私はonItStackChanged()内の位置でsetItemCheckedを呼び出すことができます。@matiashの優れた解答時に

@Override 
public void onBackStackChanged() { 
    FragmentManager fm = getFragmentManager(); 
    String name = fm.getBackStackEntryAt(fm.getBackStackEntryCount()-1).getName(); 
    mDrawerList.setItemChecked(Integer.parseInt(name),true); 
} 

public class DrawerItemClickListener implements android.widget.AdapterView.OnItemClickListener { 
    @Override 
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
     selectItem(position); 
    } 
} 

private void selectItem(int position) { 
    Fragment fragment; 

    switch (position) { 
     case 0: // Home 
      fragment = new ContentFragment(); 
      break; 
     case 1: // Another 
      fragment = new AnotherFragment(); 
      break; 
     default: // Logout 
     { 
      finish(); 

      Intent intent = new Intent(this, StartupActivity.class); 
      startActivity(intent); 

      return; 
     } 
    } 

    FragmentManager fragmentManager = getFragmentManager(); 
    fragmentManager.beginTransaction() 
      .replace(R.id.content_frame, fragment) 
      .addToBackStack(Integer.toString(position)) 
      .commit(); 

    mDrawerList.setItemChecked(position, true); 
    setTitle(mNavigationItems[position]); 
    mDrawerLayout.closeDrawer(mDrawerList); 
} 
+0

うわー、これは素晴らしいです。ありがとうございました! – Skinner927

+0

ありがとう:)あなたの答えを見つけるまで、醜い方法で十分な時間を過ごさなければならなかった。 :) – Alex

2

ビル(あなたは私の答えを+1た場合、彼/彼女を+1してください)

開始するには、我々が想定している:だからbasicly私は何をしたか、このでした

https://stackoverflow.com/a/24589081/878159から)

:私たちは、あなたが以下で現在の断片を見つけることができます Activity

getFragmentManager().addOnBackStackChangedListener(
    new FragmentManager.OnBackStackChangedListener() { 
     public void onBackStackChanged() { 
      // Update your UI here. 
     } 
    }); 

にいます

Fragment f = getFragmentManager().findFragmentById(R.id.frag_container); 
if (f instanceof CustomFragmentClass) { 
    // do something with f 
    f.doSomething(); 
} 

これで一歩近づくはずです。そして、このようなものは、あなたのNAVの引き出しへの参照を取得します。次に

nav = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.nav); 

どのようにセットアップあなたの引き出しのフラグメントのコードによって:

nav.updateSelected(position); 

updateSelected(int)方法は、あなたのNavigationDrawerFragmentクラスにあるであろうと見えるかもしれません

public void updateSelected(int position) { 
    mCurrentSelectedPosition = position; 
    if (mDrawerListView != null) { 
     mDrawerListView.setItemChecked(position, true); 
    } 
} 

注:これを行うにはさまざまな方法がありますが、これを開始する必要があります。

3

今日私は同じstrugleを持っていました。インタフェースFragmentToActivityフラグメントに実装し、私の唯一のMainActivityに実装して解決しました。

インタフェース:

public interface FragmentToActivity { 
    public void SetNavState(int id); 
} 

かけら:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    ((FragmentToActivity) getActivity()).SetNavState(R.id.nav_myitemid); //just add this line 
} 

MainActivity:

@Override 
public void SetNavState(int id) { 
    NavigationView nav = (NavigationView) findViewById(R.id.nav_view); 
    nav.setCheckedItem(id); 
} 

そして、もし

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android">  
    <group android:checkableBehavior="single"> 
     <item 
      android:id="@+id/nav_myitemid" 
      android:title="@string/home" /> 
    </group> 
</menu> 
0

これは遅れているが、代わりに、リストのナビゲーションメニューを使用している人のために、ここで私が

それをやった方法です:あなたは R.id.nav_myitemidから来ない考え、ここに私の activity_main_drawer.xmlがあるがありません
@SuppressWarnings("StatementWithEmptyBody") 
    @Override 
    public boolean onNavigationItemSelected(MenuItem item) { 
     // Handle navigation view item clicks here. 
     int position=0; 
     Fragment fragment; 
     int id = item.getItemId(); 
     if (id == R.id.nav_home) { 
      fragment=new HomeFragment(); 
      position=0; 

     } else if (id == R.id.nav_profile) { 

      fragment=new ProfileFragment(); 
      position=1; 
     } else if (id == R.id.nav_settings) { 
      fragment=new SettingsFragment(); 
      position=2; 
     } 

      getSupportFragmentManager() 
      .beginTransaction() 
      .add(R.id.relative_container, fragment) 
      .addToBackStack(""+position) 
      .commit(); 

     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     drawer.closeDrawer(GravityCompat.START); 
     return true; 
    } 

とbackstack

getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() { 
     @Override 
     public void onBackStackChanged() { 

      FragmentManager fm = getSupportFragmentManager(); 
      String name = fm.getBackStackEntryAt(fm.getBackStackEntryCount()-1).getName(); 
       if(!TextUtils.isEmpty(name)) 
      selectNavigationDrawerItem(Integer.parseInt(name)); 

     } 
    }); 

selectNavigationDrawerItem方法のためのリスナーを追加します

private void selectNavigationDrawerItem(int position){ 

       if(position==0){ 
        navigationView.setCheckedItem(R.id.nav_home); 
       } 
       else if(position==1){ 
        navigationView.setCheckedItem(R.id.nav_profile); 
       } 
       else if(position==2){ 
        navigationView.setCheckedItem(R.id.nav_settings); 
       } 

    } 
関連する問題