android - 如何为支持平板电脑和手机的应用程序提供导航

标签 android android-fragments navigation-drawer android-ui landscape-portrait

我知道以前可能会问过这个问题,但是由于我没有发现任何令人信服的内容,因此我需要再次询问。

当您还需要提供某种类型的导航面板(例如Navigation Drawer)时,如何设计将支持平板电脑和手机的应用程序?

我想我知道如何将导航抽屉与纵向使用的手机和平板电脑一起使用,因为在那种情况下,我当时只显示一个窗格(碎片)。但是对于平板电脑而言,这是完全不同的,因为您有足够的空间来显示至少两个窗格(碎片),大多数情况下,它们将以一种“重要细节”方式关联。

编辑#1



只是为了提供有关我的应用的背景信息,以及为什么我认为我需要在导航列表之外添加两个窗格。

我的应用程序的主要目标是帮助服务员下订单,这种情况在以下情况下起作用:


服务员从左侧菜单中选择“接单”选项(理想情况下为导航抽屉)
在我所谓的“内容部分”的第一部分(左窗格)中,服务员可以在他们提供的所有食物类别中进行选择(假装它是顶部的列表),然后根据所选类别,如下列表显示该特定类别下的所有菜肴。
一旦服务员点击菜,它就会自动添加到“内容部分”的第二部分(右窗格)中






知道导航抽屉的基本结构与此类似:

<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">
    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- The navigation drawer -->
    <ListView android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.DrawerLayout>


您如何处理“面向风景的平板电脑”方案?在这种情况下,您是否需要为多窗格布局使用嵌套的片段?(这听起来非常复杂)也许使用自定义库?您是否知道Git中有任何实现此功能的开源应用程序,并且可以用作参考?

编辑#2

在尝试了一些想法之后,我意识到为多个活动实现相同导航抽屉的最便捷方法是创建一个BaseActivity,该cc处理所有抽屉功能,并且所有活动都可以从中继承。

到目前为止,这是我得到的:

基础活动

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;

public class BaseActivity extends Activity {

    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private ListView mDrawerListView;

    protected void onCreate(Bundle savedInstanceState, int resLayoutID) {

        setContentView(resLayoutID);
        super.onCreate(savedInstanceState);
        setupNavDrawer();
    }

    private void setupNavDrawer() {
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerListView = (ListView) findViewById(R.id.drawer);
        mDrawerListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

        String[] rows = getResources().getStringArray(R.array.drawer_rows);
        mDrawerListView.setAdapter(new ArrayAdapter<String>(
                this, R.layout.drawer_row, rows));
        mDrawerToggle =
                new ActionBarDrawerToggle(this, mDrawerLayout,
                        R.string.drawer_open,
                        R.string.drawer_close);

        mDrawerLayout.setDrawerListener(mDrawerToggle);
        mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> listView, View row,
                                    int position, long id) {
                if (position == 0) {
                    Log.d("Menu", "European Union");
                } else {
                    Log.d("Menu", "Other Option");
                }
                mDrawerLayout.closeDrawers();
            }

        });
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}


现在,每个需要具有导航抽屉的活动都需要扩展BaseActivity

欧洲联盟活动

public class EuropeanUnionActivity extends BaseActivity{
    //...
}


同样,每个活动布局都需要在其代码中包含一个android.support.v4.widget.DrawerLayout元素,如下所示:

activity_europeanunion

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

    <include layout="@layout/main" />
    <ListView
        android:id="@+id/drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>


重要的是要提到,在要具有导航抽屉的所有活动布局中,DrawerLayout(drawer_layout)和ListView(drawer)的ID必须相同,因为这些ID被

为了简洁起见并快速测试这种方法,我使用了@CommonsWare的this example(我希望他不介意)。在这里,您可以找到BaseActivity的实现。

现在,尽管几乎所有内容都能按预期工作,但我仍无法理解为什么我将@layout/main的代码放入单独的文件listview_options中,导航抽屉根本无法关闭并点击只会使应用崩溃,并在LogCat中显示:

FATAL EXCEPTION: main
    Process: com.idealsolution.simplenavigationdrawer, PID: 17725
    java.lang.IllegalArgumentException: No drawer view found with gravity LEFT
            at android.support.v4.widget.DrawerLayout.openDrawer(DrawerLayout.java:1293)
            at android.support.v7.app.ActionBarDrawerToggle.toggle(ActionBarDrawerToggle.java:290)
            at android.support.v7.app.ActionBarDrawerToggle.onOptionsItemSelected(ActionBarDrawerToggle.java:280)
            at com.idealsolution.simplenavigationdrawer.BaseActivity.onOptionsItemSelected(BaseActivity.java:86)
            at android.app.Activity.onMenuItemSelected(Activity.java:2608)
            at com.android.internal.widget.ActionBarView$3.onClick(ActionBarView.java:167)
            at android.view.View.performClick(View.java:4456)
            at android.view.View$PerformClick.run(View.java:18465)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5086)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
            at dalvik.system.NativeStart.main(Native Method)


这是第86行:

public boolean onOptionsItemSelected(MenuItem item) {

    if (mDrawerToggle.onOptionsItemSelected(item)) { //Line 86
        return true;
    }
    return super.onOptionsItemSelected(item);
}




    


这是相同的代码
activity_europeanunion,但对ListView使用ActionBarDrawerToggle标记



<include layout="@layout/main" />
<include layout="@layout/listview_options" />




listview_options.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/menu_layout"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />
</LinearLayout>


这是我在include中尝试检索ListView的代码,但是显然不起作用:

    private void setupNavDrawer() {
            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);


           //Please pay special attention to the following two lines
            mDrawerLinearLayout = (LinearLayout) findViewById(R.id.menu_layout);
            mDrawerListView = (ListView) mDrawerLinearLayout.findViewById(R.id.drawer);


            mDrawerListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

            String[] rows = getResources().getStringArray(R.array.drawer_rows);
            mDrawerListView.setAdapter(new ArrayAdapter<String>(
                    this, R.layout.drawer_row, rows));
            mDrawerToggle =
                    new ActionBarDrawerToggle(this, mDrawerLayout,
                            R.string.drawer_open,
                            R.string.drawer_close);
            mDrawerLayout.setDrawerListener(mDrawerToggle);
            mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> listView, View row,
                                        int position, long id) {
                    //...
                    mDrawerLayout.closeDrawers();
                }

            });
            getActionBar().setDisplayHomeAsUpEnabled(true);
            getActionBar().setHomeButtonEnabled(true);
        }


欢迎任何想法和建议。
谢谢。

附言我发现this question在其中不建议使用导航抽屉。

最佳答案

对于手机和平板电脑肖像模式,您可以使用以下布局:

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

    <include layout="@layout/fragments_layout" />
    <include layout="@layout/drawer_list" />
</android.support.v4.widget.DrawerLayout>


这可能是平板电脑横向模式的布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <include layout="@layout/drawer_list" />
    <include layout="@layout/fragments_layout" />
</LinearLayout>


这是抽屉列表:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="260dp"
    android:layout_height="match_parent"
    android:layout_gravity="start" >

    <ListView
        android:id="@+id/drawer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:choiceMode="singleChoice"
        android:background="#111"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="0dp" />

</RelativeLayout>


和Fragments_layout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <fragment android:id="+@id/master_fragment" />
    <fragment android:id="+@id/detail_fragment" />
</FrameLayout>


在活动中,您必须检查自己是否处于平板电脑横向模式,并显示两个片段。否则,您将首先显示主片段,并隐藏详细信息

如果导航抽屉在所有活动上均可见,则声明一个抽象活动来处理该抽屉。然后,所有活动都从该抽象活动继承。您发布的BaseActivity是一个很好的例子

关于android - 如何为支持平板电脑和手机的应用程序提供导航,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28878027/

相关文章:

android - 将操作按钮添加到一个 fragment 的操作栏

android - 在 ViewPager 中替换 Fragment 显示黑屏?

android - 通过操作栏标题切换抽屉导航

java - 项目选定监听器上的 Android 导航菜单未触发

android - 分离所有合并的 Android 联系人

android - 无法在 Android 10 中访问 USB 摄像头

Eclipse 中的 Android 开发 : New layouts are small

android - Json 字符串到 Realm 对象,最快的方法

android - 在 Fragment 或 Activity 中使用工具栏

android - 具有向后兼容性 android 的抽屉导航