web-dev-qa-db-ja.com

ナビゲーションドロワー:タブレットで常に開くように設定

サポートライブラリのNavigation Drawerパターンを使用しています: http://developer.Android.com/training/implementing-navigation/nav-drawer.html

私はそれをタブレットで常に開くように設定しようとしていました(サイドメニューとして)

enter image description here

それは現在の実装で何か可能ですか、それとも同じコードを再利用する代わりにリストビューで新しいレイアウトと新しい構造を作成する必要がありますか?

56
Waza_Be

より大きなデバイスが異なるレイアウトファイルを持つ可能性があるという考えに基づいて、次のプロジェクトを作成しました。

https://github.com/jiahaoliuliu/ABSherlockSlides

HighLights

大きなデバイスの引き出しは常に見えるので、引き出しを用意する必要はありません。代わりに、同じ名前の2つの要素を持つLinearLayoutで十分です。

<LinearLayout
     xmlns:Android="http://schemas.Android.com/apk/res/Android"
     Android:layout_width="match_parent"
     Android:layout_height="match_parent"
     Android:orientation="horizontal">
     <ListView
             Android:id="@+id/listview_drawer"
             Android:layout_width="@dimen/drawer_size"
             Android:layout_height="match_parent"
             Android:layout_gravity="start"
             Android:choiceMode="singleChoice"
             Android:divider="@Android:color/transparent"
             Android:dividerHeight="0dp"
             Android:background="@color/drawer_background"/>
    <FrameLayout
            Android:id="@+id/content_frame"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:layout_marginLeft="@dimen/drawer_content_padding"
            />
</LinearLayout>

レイアウトファイルに引き出しがないため、アプリがレイアウト内の要素を見つけようとすると、nullが返されます。そのため、使用しているレイアウトを確認するためにブール値を追加する必要はありません。

DrawerLayout mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);

if (mDrawerLayout != null) {
    // Set a custom shadow that overlays the main content when the drawer opens
    mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
    // Enable ActionBar app icon to behave as action to toggle nav drawer
    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    // ActionBarDrawerToggle ties together the proper interactions
    // between the sliding drawer and the action bar app icon
    mDrawerToggle = new ActionBarDrawerToggle(
            this,
            mDrawerLayout,
            R.drawable.ic_drawer,
            R.string.drawer_open,
            R.string.drawer_close) {

        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view);
        }

        public void onDrawerOpened(View drawerView) {
            // Set the title on the action when drawer open
            getSupportActionBar().setTitle(mDrawerTitle);
            super.onDrawerOpened(drawerView);
        }
    };

    mDrawerLayout.setDrawerListener(mDrawerToggle);
}

以下にブール値として使用する例を示します。

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    if (mDrawerLayout != null) {
        mDrawerToggle.syncState();
    }
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (mDrawerLayout != null) {
        // Pass any configuration change to the drawer toggles
        mDrawerToggle.onConfigurationChanged(newConfig);
    }
}
47
jiahao

CommonsWareの答えに基づいて、いくつかの調整でこれを行うことができます。 1つ目は、次の3行を設定することです。

_drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
isDrawerLocked = true;
_

DrawnNoShadowの色は、アルファなしの色(0x00000000など)にすることができます。これにより、背景オーバーレイのない開いた引き出しが得られます。

次に行う必要があるのは、FrameLayoutのpadding_left値を調整することです。この目的のために、これを制御するディメンションを設定できます(デフォルトでは0dp)-この例ではR.dimen.drawerContentPaddingです。また、DrawerLayoutの幅になるR.dimen.drawerSize値も必要です。

これにより、FrameLayoutのpaddingLeft値を確認してこれらの行を呼び出すことができます。

_FrameLayout frameLayout = (FrameLayout)findViewById(R.id.content_frame);
if(frameLayout.getPaddingLeft() == (int)getResources().getDimension(R.dimen.drawerSize) {
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
    drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
    isDrawerLocked = true;
}
_

その後、有効にしたくないすべての機能をif(!isDrawerLocked)ステートメントでラップできます。これには以下が含まれます。

  • drawerLayout.setDrawerListener(drawerToggle);
  • getActionBar().setDisplayHomeAsUpEnabled(true);

最後に、静的な引き出しを使用してビューの代替レイアウトをセットアップする必要があります。例は次のとおりです。

_<FrameLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v4.widget.DrawerLayout

    Android:id="@+id/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <!-- The navigation drawer -->
    <ListView
        Android:id="@+id/left_drawer"
        Android:layout_width="@dimen/drawerSize"
        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>
<FrameLayout
    Android:id="@+id/content_frame"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_marginLeft="@dimen/drawerContentPadding"/>
_

ここでの美しさは、ターゲットとするデバイスの代替dimen.xmlファイルを設定することですべてのロジックを制御でき、変更する必要があるのは、drawerContentPaddingの値と変更されたレイアウトを提供することだけです。

注:新しいレイアウトではドロワーにオーバーレイするため、padding_leftの代わりにmargin_leftを使用することになりました。 http://derekrwoods.com/2013/09/creating-a-static-navigation-drawer-in-Android/ で、このテクニックに関する詳細なブログ投稿を参照してください。

32
methodin

setDrawerLockMode() を試して、大画面デバイスでドロワーを開いてロックします。

コメントで述べたように、DrawerLayoutはあなたのシナリオ用に設計されているとは思いません(悪い考えではありませんが、私見)。同じListViewとコンテンツをホストする別のレイアウトを使用するか、大画面のデバイスで、開いたときに重複するのではなくコンテンツをスライドさせるDrawerLayoutの独自のコピーをダウンロードして変更するそれ。

14
CommonsWare

タブレット用の代替レイアウトファイルを提供するだけです。このようにして、NavigationViewのデフォルトの動作をすべて保存できます。


ステップ1

タブレットデバイス用にこれに似た代替レイアウトファイルを作成し、_layout-w600dp-land_リソースディレクトリに配置します。

_<?xml version="1.0" encoding="utf-8"?>
<Android.support.v4.widget.DrawerLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <!--
    NavigationView and the content is placed in a horizontal LinearLayout
    rather than as the direct children of DrawerLayout.
    This makes the NavigationView always visible.
    -->

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="horizontal">
        <Android.support.design.widget.NavigationView
            Android:id="@+id/nav"
            Android:layout_width="wrap_content"
            Android:layout_height="match_parent"
            Android:fitsSystemWindows="true"
            app:headerLayout="@layout/nav_header_main"
            app:menu="@menu/activity_main_drawer"/>
        <include
            layout="@layout/app_bar_main"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent" />
    </LinearLayout>

</Android.support.v4.widget.DrawerLayout>
_



ステップ2

この手順では、引き出しの開閉がタブレット以外のデバイスでのみ機能するように、十分な変更を行います。

ステップ2.1

次のコンテンツをvaluesディレクトリの新しい値リソースファイルに追加し、_config_ui.xml_という名前を付けます

_<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isDrawerFixed">false</bool>
</resources>
_

それは非タブレットデバイス用でした。タブレットデバイスの場合、同じ名前の別のデバイスを作成し、_values-w600dp-land_に配置します。

_<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isDrawerFixed">true</bool>
</resources>
_

引き出しが属するアクティビティのクラスに新しいフィールドを作成します
_private boolean isDrawerFixed;_
そしてそれを次のように初期化します
isDrawerFixed = getResources().getBoolean(R.bool.isDrawerFixed);

これで、デバイスがif (isDrawerFixed){}のような単純なテーブル型か非タブレット型かを確認できます。

ステップ2.2

このようなifステートメントでアクションバーのトグルボタンを設定するコードをラップします。

_if (!isDrawerFixed) {
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();
}
_

このような別のifステートメントでアイテムがクリックされたときに引き出しを閉じるコードをラップします。

_if (!isDrawerFixed) {
    drawer.closeDrawer(GravityCompat.START);
}
_




最終結果は、このようになります。

output

6
Anees

以前の回答は良いのですが、プロジェクトに実装するときにいくつかの問題に直面したため、ソリューションを共有したいと思います。まず、カスタムドロワーを定義する必要があります。

public class MyDrawerLayout extends DrawerLayout {
    private boolean m_disallowIntercept;

    public MyDrawerLayout (Context context) {
        super(context);
    }

    @Override
    public boolean onInterceptTouchEvent(final MotionEvent ev) {
        // as the drawer intercepts all touches when it is opened
        // we need this to let the content beneath the drawer to be touchable
        return !m_disallowIntercept && super.onInterceptTouchEvent(ev);
    }

    @Override
    public void setDrawerLockMode(int lockMode) {
        super.setDrawerLockMode(lockMode);
        // if the drawer is locked, then disallow interception
        m_disallowIntercept = (lockMode == LOCK_MODE_LOCKED_OPEN);
    }
}

次に、次のような基本的なアクティビティレイアウト(前の回答からの任意のレイアウトなし)に配置します。

<MyDrawerLayout 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <!--We must define left padding for content-->
    <FrameLayout
        Android:id="@+id/content_frame"
        Android:paddingStart="@dimen/content_padding"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"/>

    <Android.support.design.widget.NavigationView
        Android:layout_width="wrap_content"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        Android:fitsSystemWindows="true"
        app:menu="@menu/menu_nav" />

</MyDrawerLayout>

ここでのコンテンツのパディングは、NavigationViewの場合、縦向きでは0dp、横向きでは約300dpです(経験的に設定)。適切なvaluesフォルダーでそれらを定義します。

values/dimens.xml-

<dimen name="content_padding">0dp</dimen>

values-land/dimens.xml-

<dimen name="content_padding">300dp</dimen>

最後に、アクティビティ内のドロワーをロックします。

    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
        mDrawerLayout.setScrimColor(0x00000000); // or Color.TRANSPARENT
        isDrawerLocked = true;
    } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        mDrawerLayout.setScrimColor(0x99000000); // default shadow
        isDrawerLocked = false;
    }
4
mister_potato