The Material Design specs によれば、モバイルデバイスでのNav Drawerの幅は
サイドナビゲーションの幅=画面の幅-アプリバーの高さ
これをアンドロイドにどのように実装しますか?
2つの部分的な解決策があります。最初はハックな方法です。包含アクティビティに次のコードを配置します。
if(Build.VERSION.SDK_INT> Build.VERSION_CODES.HONEYCOMB_MR1){ final Display display = getWindowManager()。getDefaultDisplay(); final Point size = new Point() ; display.getSize(size); final ViewGroup.LayoutParams params = mDrawerFragment.getView()。getLayoutParams(); params.width = size。 x-getResources()。getDimensionPixelSize( R.dimen.abc_action_bar_default_height_material ); mFragmentUserList.getView()。setLayoutParams(params); }
ただし、これは2番目のレイアウトサイクルを引き起こし、Gingerbreadでは機能しません。最適ではありません。
2番目のソリューションでは、フラグメントとドロワーレイアウトの間にスペースを追加します。ただし、ユーザーが押してメインアプリに戻ることができる影とスポットを移動します。また、「ハンバーガー」アイコンを押すとクラッシュします。最適ではありません。
より良い解決策、できればスタイルとxmlを含む解決策はありますか?
Android Design Support Library を使用すると、正しいサイズ設定を含むナビゲーションドロワーの実装が非常に簡単になりました。 NavigationView を使用し、メニューリソースから引き出しを作成する機能を使用する(例 here )リスト(ListView、RecyclerViewなど)。これにより、NavigationViewが引き出しのサイズを管理します。
ListViewにラップされたNavigationViewの使用例を次に示します。
<?xml version="1.0" encoding="utf-8"?>
<Android.support.v4.widget.DrawerLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:id="@+id/navdrawer_layout"
Android:fitsSystemWindows="true">
<!-- Layout where content is shown -->
<RelativeLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<include Android:id="@+id/toolbar"
layout="@layout/toolbar" />
<FrameLayout
Android:id="@+id/content_frame"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_below="@id/toolbar" />
<!-- Toolbar shadow for pre-Lollipop -->
<View style="@style/ToolbarDropshadow"
Android:layout_width="match_parent"
Android:layout_height="3dp"
Android:layout_below="@id/toolbar" />
</RelativeLayout>
<Android.support.design.widget.NavigationView
Android:id="@+id/navigation_view"
Android:layout_width="wrap_content"
Android:layout_height="match_parent"
Android:layout_gravity="start">
<ListView
Android:id="@+id/navdrawer_list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:choiceMode="singleChoice"
Android:dividerHeight="0dp"
Android:divider="@null"/>
</Android.support.design.widget.NavigationView>
</Android.support.v4.widget.DrawerLayout>
このようにすると、NavigationViewsのサイズ設定を使用し、独自の引き出しリストを使用できます。引き出しリストをメニューリソースから作成する方がはるかに簡単ですが(例 here )、リストアイテムにカスタムビューを使用することはできません。
私はXMLスタイルの宣言を使用してソリューションを作成することができましたが、それも少しハックです。私のアプローチは、設定された幅を適用する代わりにマージンを使用して、手動でレイアウトを計算するコードを記述することを回避することでした。これを機能させる方法を強調する基本的なスタイルルールを作成しました。
残念ながら、DrawerLayoutは現在64dpの最小マージンを適用しています。このアプローチを機能させるには、ナビゲーションドロワーに必要な幅を取得できるように、その値を負のマージンでオフセットする必要があります。願わくば、これが将来解決できることを願っています( 誰かがそれに関して問題を提起しています )。そうすれば、マージンのabc_action_bar_default_height_material
ディメンション参照を参照できます。
次の手順を実行します:
次の寸法とスタイルの定義を追加します:
values/dimens.xml
<!-- Match 56dp default ActionBar height on portrait orientation -->
<dimen name="nav_drawer_margin_offset">-8dp</dimen>
values-land/dimens.xml
<!-- Match 48dp default ActionBar height on landscape orientation -->
<dimen name="nav_drawer_margin_offset">-16dp</dimen>
values/styles.xml
<!-- Nav drawer style to set width specified by Material Design specification -->
<style name="NavDrawer">
<item name="Android:layout_width">match_parent</item>
<item name="Android:layout_marginRight">@dimen/nav_drawer_margin_offset</item>
</style>
values-sw600dp/styles.xml
<!-- Margin already matches ActionBar height on tablets, just modify width -->
<style name="NavDrawer">
<item name="Android:layout_width">320dp</item>
<item name="Android:layout_marginRight">0dp</item>
</style>
プロジェクトに上記のルールを追加したら、ナビゲーションドロワービューでNavDrawerスタイルを参照できます:
layout/navigation_drawer.xml(またはナビゲーションドロワーに使用されている他の適切なビュー)
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/navigation_drawer"
style="@style/NavDrawer"
Android:layout_height="match_parent"
Android:layout_gravity="start"
Android:choiceMode="singleChoice"
Android:divider="@Android:color/transparent"
Android:dividerHeight="0dp"
Android:background="#FFF"
/>
より単純なソリューションを探した後、非常に明確な記事を見つけました: Material Navigation Drawer sizing 。
ここに:
Nexus 5の画面はニース640 x 360 dp(xxhdpi)で、アプリバーの高さは56 dpです。したがって、ナビゲーションドロワーは次のようになります。
[dpの幅] = 360dp — 56dp = 304dp
Nexus 4は、代わりに640 x 384 dp(xhdpi)画面を備えています。同じ56dpアプリバーの高さ。そのナビ引き出し?
[dpの幅] = 384dp — 56dp = 328dp
では、Googleデザイナーはどのようにしてそれぞれ288dpと304dpの幅を思いついたのでしょうか?何も思いつきません。
一方、Googleアプリは私の数学に同意するようです。ああ、あなたはこの中で最も面白いことを知っていますか? iPhone(画面の高さは異なりますが、320 dpの幅は一定です)は、264dpのnav引き出しがあると正しくマークされます。
基本的に、ナビゲーションドロワーに関するいくつかのガイドラインが矛盾していること、および次のルールを使用して計算を回避できることを示しています。
基本的に、ナビゲーションドロワーには常に-sw360dpで304dpを使用し、-sw384dpで320dpを使用できます。
彼らはすでに仕様を更新しており、ナビゲーションドロワーの幅は次のとおりです。
Math.min(screenWidth — actionBarSize, 6 * actionBarSize);
さて、これを理解して実装するのは非常に難しいと感じました。残念なことに、Matthewのソリューションは私のナビゲーションドロワーを横長にしすぎており、Googleの慣行に反しているように見えました。つまり、ナビゲーションの幅はデバイスの最小幅によって決まります。いずれにしても、私のマニフェストで構成を無効にしたため、私の場合は機能しません。そこで、次のコードを使用してnavの幅を動的に変更することにしました。
私のアプリは電話専用であり、320dpが最大幅であることに決めました。これが、両方の向きで56dpツールバーの高さに決めた理由でもあります。
それが誰かを助け、それが私を引き起こした不必要なストレスを避けることができることを願っています。
navDrawLayout.post(new Runnable()
{
@Override
public void run() {
Resources r = getResources();
DisplayMetrics metrics = new DisplayMetrics();
if(r.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
float screenWidth = height / r.getDisplayMetrics().density;
float navWidth = (screenWidth - 56);
navWidth = Math.min(navWidth, 320);
int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics());
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams();
params.width = newWidth;
navDrawLayout.setLayoutParams(params);
}
if(r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int width = metrics.widthPixels;
float screenWidth = width / r.getDisplayMetrics().density;
float navWidth = screenWidth - 56;
navWidth = Math.min(navWidth, 320);
int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics());
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams();
params.width = newWidth;
navDrawLayout.setLayoutParams(params);
}
}
}
);
ナビゲーションドロワーの幅は、デバイスの最小の幅、向き、およびAndroidバージョン。