【问题标题】:Multiple activities (not fragments) with a NavigationDrawer. How to show currently selected Activity?带有 NavigationDrawer 的多个活动(不是片段)。如何显示当前选择的活动?
【发布时间】:2015-02-03 10:35:54
【问题描述】:

在决定我们将使用导航抽屉或汉堡菜单之前,我有一个包含很多活动的应用程序。我不想使用片段重做整个应用程序,所以我决定采用此答案中使用的方法: Same Navigation Drawer in different Activities

编辑:现在,这个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); 在 Intent 启动前或启动后不起作用。

奇怪的是:如果我当前在 Activity1,打开 NavDrawer 并选择 Activity2。我登陆Activity2,打开NavDrawer,看到“Activity2”没有被选中。我单击返回按钮,进入 Activity1,打开 NavDrawer 并看到“Activity2”被选中。

这意味着setItemChecked 有效,但在启动的新活动中无效。

目前我将该位置作为 Intent extra 传递,并专门设置选中的位置,如 LibraryActivity 中的注释部分。 这可行,但似乎可以解决。请告诉我在 NavDrawerBaseActivity 类而不是在扩展它的每个 Activity 中是否有正确/更好的方法。

【问题讨论】:

    标签: android navigation-drawer


    【解决方案1】:

    不要在每个活动中放置导航抽屉,这违背了扩展 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,然后它们要么必须扩展 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)

    然后单击/选择您有 switch/if-else 语句的侦听器:

     @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
         view.setSelected(true)  
    
         //....the rest of your code here
    }
    

    最后,我建议您先尝试一下,因为如果您使用普通的 listView,这将是最简单的方法:

    <ListView android:id="@+id/my_list"
        android:choiceMode="singleChoice" 
        android:listSelector="@android:color/blue" />
    

    EDIT2:

    现在要保留所选项目的状态...因此,抽屉上的每个操作似乎都会重新实例化不理想的基类。我们需要以某种方式保留实例状态,使其几乎充当单例。我尝试覆盖 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);
    }
    

    【讨论】:

    • 哪个 XML 有抽屉?用户永远不会看到 NavDrawerBaseActivity,因此没有布局。所以(比如说)扩展 NavDrawerBaseActivity 的 Activity1 应该有&lt;android.support.v4.widget.DrawerLayout...&gt; &lt;ListView android:id="@+id/left_drawer".../&gt; &lt;/android.support.v4.widget.DrawerLayout&gt; 对吗?
    • 啊,你错了……用户确实看到了 NavDrawerBaseActivity……因为它是你的导航抽屉! :) 所以基本上你的 Activity1、Actvity2 等必须只扩展 NavDrawerBaseActivity 等等。它应该与 xml 或 android 代码中的任何形式的 Drawer 代码完全没有关系,所有这些都应该在 NavDrawerBaseActivity 内部,所以如果 NavDrawerBaseActivity 没有布局,你必须在其中创建一个带有抽屉的布局,就像您目前在 Activity1 等中执行...请记住,与抽屉相关的所有代码都必须仅在 NavDrawerBaseActivity
    • 如果您不明白,请告诉我,以便我尝试更清楚地解释或编辑我的答案。请尝试理解继承会发生什么以及扩展类时会发生什么。任何扩展基类的类都会获得基类的行为/外观等以及它自己的......
    • 好的,所以你说我需要一个用于 NavDrawerBaseActivity 的 layout.xml 以及另一个用于 Activity1 的 layout.xml。所以我应该在两者的onCreate 方法中调用setContentView 吗?最新的setContentView 电话不会决定最终的布局吗?继承,AFAIK,不结合 NavDrawerBaseActivity 和 Activity1 的 layout xmls
    • 请再看一下我发布的代码。 NavDrawerBaseActivity 已经实现了您在回答中建议的内容。方法NavDrawerBaseActivity.DrawerItemClickListener.onItemClick 有一个类似switch 的if-else 构造,我试图在启动新活动之前执行mDrawerList.setItemChecked(position, true);。它不起作用(因此被注释掉了)。新活动中的 NavDrawer 没有选择任何内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    • 2019-07-08
    • 2017-06-08
    相关资源
    最近更新 更多