在按下后更新导航抽屉的选定状态

时间:2015-01-07 17:02:40

标签: android android-fragments navigation navigation-drawer onbackpressed

在按下后是什么方法处理导航抽屉的选定状态?

我有一个带有n个条目的导航抽屉(在列表视图中),就像Android Studio中的SDK示例一样。 当我点击导航抽屉条目时,我希望它们被添加到后台堆栈,所以我可以回到它们。

在onNavigationDrawerItemSelected(int pos)中我有

        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将再次显示,但仍然在导航抽屉中选择了B.

如何在按下后更新抽屉的选择状态?

不知怎的,我需要调用mDrawerListView.setItemChecked(position,true);或NavigationDrawerFragment.selectItem(int position)。但到了哪个位置?我怎么记得呢?

拦截onBackPressed?

@Override
    public void onBackPressed() {}

但我怎么知道哪个片段再次活跃?以及它对应的位置。

有一些简单的解决方案我是盲目的看到的吗?似乎将back与导航抽屉结合使用并更新选择状态是标准模式。

7 个答案:

答案 0 :(得分:8)

“正确返回导航”文档的Implement Back Navigation for Fragments部分介绍了此模式。

  

如果您的应用程序更新其他用户界面元素以反映   片段的当前状态,例如操作栏,请记住   提交事务时更新UI。你应该更新   除了何时更改后堆栈后的用户界面   你提交交易。 你可以在什么时候听   通过设置a来恢复FragmentTransaction   FragmentManager.OnBackStackChangedListener

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

这将是刷新导航抽屉中当前选项的适当位置。

答案 1 :(得分:6)

今天我有同样的问题。我通过在每个片段和我唯一的MainActivity中实现接口FragmentToActivity来解决它。

<强>接口

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

如果你不知道R.id.nav_myitemid来自哪里,这是我的 activity_main_drawer.xml

<?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>

答案 2 :(得分:5)

我在尝试找出这个问题的解决方案时遇到了很多麻烦,而我最终使用的解决方案并不是很好的&#34;在我看来,但它的确有效。

在我的应用程序中,当我将片段添加到backstack时,我最终在导航抽屉中添加了片段位置。这样我可以使用onBackStackChanged()中的位置调用setItemChecked。基本上我所做的就是这个:

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

答案 3 :(得分:3)

以@matiash的优秀答案为基础(如果你给我的答案+1,请务必给他/她+1)

首先,我们假设我们在Activity

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

您可以使用以下内容找到当前片段:

(来自https://stackoverflow.com/a/24589081/878159

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

这应该让你更近一步。然后这样的东西会让你引用你的导航抽屉:

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

注意:有很多方法可以做到这一点,但这应该可以让你开始。

答案 4 :(得分:0)

这已经晚了,但是对于那些使用导航菜单而不是列表的人来说,这就是我做的方式

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

     }

答案 5 :(得分:0)

这是Kotlin的解决方案。

在要被抽屉选中并突出显示的片段中,只需执行以下操作:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val navView: NavigationView = activity!!.findViewById(R.id.nav_view)
    navView.setCheckedItem(R.id.name_of_this_fragment)

    ...
}

答案 6 :(得分:0)

其实很简单。您已经拥有 Drawer 布局中的导航视图。对于按下的每个项目,它会打开相应的片段,对吗? 现在转到每个片段的 onCreateView 并执行此操作...

NavigationView navigationView = getActivity().findViewById(R.id.navigation_view);
        navigationView.setCheckedItem(R.id.this_fragment's_item);

此外,在您处理项目点击的主活动中,使用 if 语句,以便

if (navigation_view.getMenu().findItem(R.id.account_nav).isChecked())   
  drawer_layout.closeDrawer(GravityCompat.START);

以上避免了在自身之上创建片段的多个实例。