【Android】NavigationViewを使わないで、スライドするメニューをつくる

スライドするメニューは`DialogFragment`で作成しました。
Activityの上に、DialogFragmentが被さるイメージです。

# アニメーションの作成
## 左から右へスライドするアニメーション(res/anim/slide_in.xml)

```xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="-100%"
        android:toXDelta="0%" />

    <alpha
        android:duration="250"
        android:fromAlpha="0.8"
        android:toAlpha="1.0" />
</set>

```

## 右から左へスライドするアニメーション(res/anim/slide_out.xml)

```xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="0%"
        android:toXDelta="-100%" />

    <alpha
        android:duration="250"
        android:fromAlpha="1.0"
        android:toAlpha="0.2" />
</set>
```

## themes.xmlに、作成したアニメーションのstyleを定義

```xml
<resources xmlns:tools="http://schemas.android.com/tools">
    ....
    <style name="SlideInMenuAnimation">
        <item name="android:windowEnterAnimation">@anim/slide_in</item>
        <item name="android:windowExitAnimation">@anim/slide_out</item>
    </style>
    ....
</resources>
```

# スライドするメニューの作成
## レイアウト
```xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/slide_menu"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    tools:context=".SlideInMenuFragment">

    <LinearLayout
        android:id="@+id/menu_area"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- ActionBarと同じ高さのスペースの余白 -->
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/design_default_color_primary"
            android:minHeight="?android:attr/actionBarSize" />

        <!-- メニュー部分 -->
        <ListView
            android:id="@+id/menu_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</FrameLayout>
```

## DialogFragmentの実装
```java
public class SlideInMenuFragment extends DialogFragment {

    public SlideInMenuFragment() {
        // Required empty public constructor
    }

    public static SlideInMenuFragment newInstance() {
        SlideInMenuFragment fragment = new SlideInMenuFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        Dialog dialog = new Dialog(getActivity());
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setContentView(R.layout.fragment_slide_in_menu);

        // 全画面表示のDialogで、左寄せに配置する
        Window window = dialog.getWindow();
        window.getAttributes().windowAnimations = R.style.SlideInMenuAnimation;
        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        window.setGravity(Gravity.TOP | Gravity.START);
        window.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);

        // LayoutのルートViewを設定
        FrameLayout rootView = dialog.findViewById(R.id.slide_menu);
        onViewCreated(rootView, savedInstanceState);
        return dialog;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        String[] menuArray = {"メニュー", "メニュー", "メニュー"};
        // メニューの内容を設定する
        ListView menu = view.findViewById(R.id.menu_list);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, menuArray);
        menu.setAdapter(adapter);
    }
}
```

# MainActivityで呼ぶ

```java
public class MainActivity extends AppCompatActivity {

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

        // ActionBarの左端にボタンを設定する
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            // ↓アイコンは標準のソートアイコン使ってますが、≡ に変えたらいい感じになります。
            actionBar.setHomeAsUpIndicator(android.R.drawable.ic_menu_sort_by_size);
        }
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            // メニュー表示
            FragmentManager fragmentManager = getSupportFragmentManager();
            SlideInMenuFragment fragment = SlideInMenuFragment.newInstance();
            fragment.show(fragmentManager, fragment.getClass().getSimpleName());
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
}
```

# 結果
アクションバーの左にあるアイコンをクリックすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/827233/146824e4-dadf-378a-62ae-b55dcfab1d19.png)
　↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/827233/ab70d124-4894-9ca6-964f-cea8df6ed0e5.png)
メニューが開きます。背景の透明部分をタップすると、メニューが閉じます。

### 注意
この実装だとジェスチャー操作して、メニューがピロピロと出てこないです。
自前でメニューを色々する必要があったのでこの方法を実装しましたが、
やっぱりNavigationView 使った方がいいです。