当前位置: 首页 > 知识库问答 >
问题:

具有NavigationDrawer的多个活动(不是片段)。如何显示当前选中的活动?

慕弘义
2023-03-14

我有一个应用程序相当多的活动之前,它决定我们将使用导航抽屉或汉堡包菜单。我不想使用片段重做整个应用程序,所以我决定采用这个答案中使用的方法:在不同的活动中使用相同的导航抽屉

编辑:现在,这一个https://stackoverflow.com/a/23477100/1371585

并且创建了一个名为NAVDrawerBaseActivity的基本活动。代码如下:

    public class NavDrawerBaseActivity extends MyBaseActivity {

    public DrawerLayout mNavDrawerLayout;
    public ListView mDrawerList;
    public String[] mMenuItems;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.navdrawer_activity);

        mNavDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mMenuItems = getResources().getStringArray(R.array.optionsmenu_array);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                R.layout.drawer_list_item, mMenuItems);
        mDrawerList.setAdapter(adapter);
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener(this));

        super.onCreate(savedInstanceState);
    }

    private class DrawerItemClickListener implements
            ListView.OnItemClickListener {

        private DrawerItemClickListener(Context context) {
            mContext = context;
        }

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {

            String textClicked = ((TextView) view).getText().toString();
            view.setSelected(true);

            if (textClicked.equalsIgnoreCase(mContext
                    .getString(R.string.optionsmenu_library))) {


                Intent libraryIntent = new Intent(mContext,
                        LibraryActivity.class);
                libraryIntent.putExtra("navdrawerposition", position);
                startActivity(libraryIntent);
                mNavDrawerLayout.closeDrawers();
                mDrawerList.setItemChecked(position, true); //Not working


            } else if (textClicked.equalsIgnoreCase(mContext
                    .getString(R.string.optionsmenu_settings))) {
                // TODO: open activity and close the drawer
            } else if (textClicked.equalsIgnoreCase(mContext
                    .getString(R.string.optionsmenu_logout))) {
                // TODO: open activity and close the drawer
            } 
        }

        private Context mContext;
    }
}

下面是布局文件navdrawer_activity.xml

    <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    >

    <FrameLayout
        android:id="@+id/activity_frame"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

    <!-- The navigation drawer -->

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" 
        />


</android.support.v4.widget.DrawerLayout>

每个活动都扩展了NavDrawerBaseActivity,而不使用SetContentView,如下所示:

 public class LibraryActivity extends NavDrawerBaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Not setting content view here, since its already set in
        // NavDrawerBaseActivity
        FrameLayout frameLayout = (FrameLayout) findViewById(R.id.activity_frame);
        // Inflating the Camera activity layout
        LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View activityView = layoutInflater
                .inflate(R.layout.library_page, null, false);
        // Adding the custom layout of this activity to frame layout set in
        // NavDrawerBaseActivity.
        frameLayout.addView(activityView);


//      Only this part of the code is doing what I want.

//      int drawerSelectedPosition = getIntent().getIntExtra(mNavDrawerPosExtraName, -1);
//      if(drawerSelectedPosition > -1){
//          mDrawerList.setItemChecked(drawerSelectedPosition, true);
//      }
    }

}

我的问题:如何正确地突出显示NavDrawer视图中的当前活动?启动意图之前或启动意图之后的MDrawerList.SetItemChecked(position,true);不起作用。

奇怪的部分是:如果我当前在Activity1中,打开NavDrawer并选择Activity2。我登陆Activity2,打开NavDrawer,看到“Activity2”没有被选中。我点击后退按钮,登陆Activity1,打开NavDrawer并看到“Activity2”被选中。

这意味着SetItemChecked可以工作,但不能在启动的新活动中工作。

当前,我将该位置作为一个额外的意图传递,并特别设置了checked位置,如libraryactivity中的注释部分。这是可行的,但似乎是一个工作周围。请告诉我在NavDrawerBaseActivity类中,而不是在扩展它的每个活动中,是否有一种正确的/更好的方法来做到这一点。

共有1个答案

公孙宏远
2023-03-14

不要在每个活动中都放入nav抽屉,这会使扩展NavDrawerBaseActivity类的目的落空。因为您的所有其他活动都扩展了这个基类,所以它们应该自动继承它的所有功能。因此,只将抽屉放入NAVDrawerBaseActivity中。然后,在抽屉的xml中,可以指定每个按钮的操作,如下所示:

<Button
        style="@style/drawerBtn"
        android:id="@+id/activity1Btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick">

或者简单地在抽屉上设置一个onClick监听器,比如:

myDrawer.setOnClickListener().........etc

然后,在onClick处理程序(位于NavDrawerBaseActivity类内部)中,您可以简单地检查按下了哪个按钮并打开关联的活动,如下所示:

//remember, if you used the onClickListener you have to use @Override at the top of this function
public void onClick(View item) {

    //lets see which button on the drawer was pressed....item is the item that triggered the click
    switch (item.getId()) {
        case R.id.activity1Btn:
            Intent intent1 = new Intent(this, Activity1.class);
            startActivity(intent1);
            break;
        case R.id.activity2Btn:
            Intent intent2 = new Intent(this, Activity2.class);
            startActivity(intent2);
            break;
        case R.id.activity3Btn:
            Intent intent3 = new Intent(this, Activity3.class);
            startActivity(intent3);
            break;
    }
}

请记住,Activity1、Activity2、Activity3必须扩展NavDrawerBaseActivity,然后NavDrawerBaseActivity,然后NavDrawerBaseActivity必须扩展Activity,或者扩展另一个类,后者又扩展Activity.....如此等等。然后还可以在此开关中设置诸如mDrawerList.setItemChecked(position,true)之类的东西。所以简而言之,让所有抽屉的事情只发生在这个类中,并且通过扩展它来简单地“实现”这个类,记住这个类包含所有“子”类/活动中通用的所有功能,它们都继承了这个行为

编辑:

如果要突出显示抽屉中的项目,则必须在项目上使用setSelected(true)。如果需要,可以通过在drawables文件夹中创建选择样式来定义自定义选择状态。然后将此样式设置为列表项示例的背景:

<!-- drawable/myStyles.xml-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true" android:state_pressed="true" android:drawable="@color/blue"/> <!--item selected state--> 
    <item android:state_enabled="true" android:state_focused="true" android:drawable="@color/blue"/> <!--item selected state--> 
    <item android:state_enabled="true" android:state_selected="true" android:drawable="@color/blue"/> <!--item selected state--> 
    <item android:state_focused="false" android:state_pressed="false" android:drawable="@color/gray"/> <!--item NOT selected state--> 
</selector>

和您的抽屉物品:

<LinearLayout
    android:id="@+id/my_drawer_item"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/myStyles">

然后在switch/if-else语句中将所选项设置为MyNewSelectedView.SetSelected(true)。您可能必须手动取消选择旧的,如MyOldSelectedItem.SetSelected(false)

然后单击/Selected listener,在这里切换/if-else语句:

 @Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
     view.setSelected(true)  

     //....the rest of your code here
}
<ListView android:id="@+id/my_list"
    android:choiceMode="singleChoice" 
    android:listSelector="@android:color/blue" />

编辑2:

现在要保留selected items状态...所以看起来抽屉上的每个操作都重新初始化了基类,这并不理想。我们需要以某种方式保留实例状态,使其几乎作为一个单例运行。我尝试过重写onSaveInstanceState和使用singleInstance启动程序状态,但都不起作用。因此,在此期间,我想出了一个解决方案,将当前的选择作为静态变量保存在内存中:

private static int mCurrentSelectionIndex = 0; //this is defined at the top of your class with your default selected screen ie the first item in the list.

//then in setContentView after assigning the drawer layout you set the currentSelection
@Override
public void setContentView(final int layoutResID) {
    //...... first assign the layouts ie mDrawerList = findViewByLayout(R.id.myDrawerList) etc

    mDrawerList.setSelection(mCurrentSelectionIndex); 
      // OR:
    mDrawerList.setItemChecked(mCurrentSelectionIndex, true);
}

//then in onClick()
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    mCurrentSelection = position;
    item.setSelected(true);
}
 类似资料:
  • 我在中有一个可以膨胀的工具栏。我有一个名为的菜单,它会膨胀,只显示一个图标。 当用户单击打开片段时。我有另一个菜单,它有两个图标。 当我在片段中膨胀friends菜单时,它仍然显示菜单中的图标。 非常感谢您的任何建议,

  • 我读过很多关于这方面的文章,但也有2012年或更早的文章。 (我只是打算从数据库中读取和插入一些数据。)

  • 有什么理由不不分青红皂白地这样做而不重新评估我使用片段的每个单独的情况吗?

  • 在我的应用程序中,我使用了一个活动和两个片段。该应用程序使用带有容器的布局,因此片段是通过事务添加的。第一个片段包含列表视图,另一个片段包含列表视图项的详细视图。两个片段都使用setRetainInstance(true)。片段是通过替换事务添加的,并设置了addToBackStack(null)。列表片段包含一个实例变量,其中包含列表的一些信息。现在我正在切换到详细并按回,实例变量为null。我

  • 我试图从活动中隐藏/显示片段中的按钮,但它给了我以下异常。 android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图。 家庭活动 类别片段 代码太大,无法在此处发布。这就是为什么我只在发现问题的地方发布代码。 我能够获得新设计按钮实例。令我震惊的是,如果尝试玩按钮实例(可见/消失),它会给我上述异

  • 我正在建立一个简单的应用程序,我想从片段回到物理按钮的活动。我该怎么做?我试图杀死碎片,但它不起作用。