Android で Snackbar の表示位置 & 幅を Material Design ガイドラインに則ってカスタマイズしてみた件

# [Snackbars](https://material.io/design/components/snackbars.html) - [Material Design](https://material.io/)

* 画面下部で一時的に表示されるアプリケーションのプロセスに関する簡単なメッセージ

![snackbars-container-do-1.png](https://qiita-image-store.s3.amazonaws.com/0/6881/5266e198-ef1f-ba70-8c83-53544d641d7b.png)

---

## 推奨 :o:

* コンポーネント上部での表示が理想

| [FloatingActionButton](https://developer.android.com/reference/android/support/design/widget/FloatingActionButton) | [BottomAppBar](https://material.io/design/components/app-bars-bottom.html) |
|:---:|:---:|
|![snackbars-layout-fab.png](https://qiita-image-store.s3.amazonaws.com/0/6881/b96fa054-e4ab-fd9c-a889-772b33861952.png)|![snackbars-layout-do-navigation.png](https://qiita-image-store.s3.amazonaws.com/0/6881/89c85bc3-fbed-fef9-28b3-a6e8519fee6f.png)|

---

### 模範例 :thumbsup:

* [Google Keep](https://play.google.com/store/apps/details?id=com.google.android.keep)（Android スマホにて）

![Screenshot_1526031261.png](https://qiita-image-store.s3.amazonaws.com/0/6881/3a8b4279-6a9a-e8a8-f136-f95177c6716e.png)

---

## 駄目 :x:

* コンポーネントの前面に被せるのは厳禁

| [FloatingActionButton](https://developer.android.com/reference/android/support/design/widget/FloatingActionButton) | [BottomAppBar](https://material.io/design/components/app-bars-bottom.html) |
|:---:|:---:|
|![snackbars-layout-fab-dont-1.png](https://qiita-image-store.s3.amazonaws.com/0/6881/84b83798-299d-2e60-56f8-4714619511e3.png)|![snackbars-layout-don-t-bottom-bar.png](https://qiita-image-store.s3.amazonaws.com/0/6881/3e8f650a-e59f-e996-20f3-7929b2ff2804.png)|

---

### 疑惑 :police_car:

* [Google Keep](https://play.google.com/store/apps/details?id=com.google.android.keep)（Android タブレットにて）

![20180511_172225.jpg](https://qiita-image-store.s3.amazonaws.com/0/6881/ded534c6-c6d2-a141-c219-1c22da24ba8d.jpeg)

---

## アカンやつ :no_good:

* 画面底の永続的要素を押し上げて、ひょっこりはん（例：[BottomAppBar](https://material.io/design/components/app-bars-bottom.html)）

![snackbars-layout-don-t-push-bottom-bar-1.png](https://qiita-image-store.s3.amazonaws.com/0/6881/ef78fe0c-87e8-65b6-4db2-400b57a0c9f1.png)

---

### 事案 :warning:

* [Google Keep](https://itunes.apple.com/jp/app/google-keep/id1029207872?mt=8)（[iPhone 5s](https://support.apple.com/kb/SP685) にて）

![IMG_0008.PNG](https://qiita-image-store.s3.amazonaws.com/0/6881/0b65352b-5278-db6a-62ff-4169e9b38337.png)

---

# :one: 任意の位置から

* [Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) を画面の底からではなく、指定の場所から表示させたい :pray:

---

## 方法

1. レイアウト内で [Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) を表示させたい地点に [CoordinatorLayout](https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout) を配置
2. [Snackbar.make](https://developer.android.com/reference/android/support/design/widget/Snackbar#make) メソッドの第１引数に、レイアウト内に設置した [CoordinatorLayout](https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout) を渡す

### 参考 :link:

* https://stackoverflow.com/a/31496283/5897175

---

## サンプル

* [BottomNavigationView](https://developer.android.com/reference/android/support/design/widget/BottomNavigationView) の上部から [Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) を表示する

### 手法

* [Android Studio](https://developer.android.com/studio/?hl=ja) 内のテンプレート **Bottom Navigation Activity** を少し修正します :tools:

---

### 目標

* [Google フォト](https://play.google.com/store/apps/details?id=com.google.android.apps.photos)（Android タブレットでの挙動）

![Screenshot_1526083703.png](https://qiita-image-store.s3.amazonaws.com/0/6881/2badb698-bac7-45e3-195e-e53f3b9d7685.png)

---

### コード

``` activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinatorLayout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <android.support.design.widget.BottomNavigationView
        android:id="@id/bottomNavigationView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/navigation" />

</android.support.constraint.ConstraintLayout>
```

---

``` MainActivity.kt
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        bottomNavigationView.setOnNavigationItemSelectedListener({ menuItem ->
            Snackbar.make(coordinatorLayout, menuItem.title, Snackbar.LENGTH_SHORT).show()
            true
        })
    }
}
```

---

### 実行結果

![Screenshot_1525876113.png](https://qiita-image-store.s3.amazonaws.com/0/6881/b0686a65-9d13-ebe1-9cba-21558d28d0c4.png)


---

# :two: 任意の幅で

- [CoordinatorLayout](https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout) のサイズを調整することで、表示される [Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) の幅を変更できます :slight_smile:

---

## 幅を `"wrap_content"` にした場合

- [CoordinatorLayout](https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout) を `android:layout_width="wrap_content"` にすると、表示される [Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) の幅がテキストの長さ分になります :straight_ruler:

---

### コード

``` activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinatorLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <android.support.design.widget.BottomNavigationView
        android:id="@id/bottomNavigationView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/navigation" />

</android.support.constraint.ConstraintLayout>
```

---

### 実行結果

| 例 ① | 例 ② |
|:------:|:-------:|
|![Screenshot_1525876227.png](https://qiita-image-store.s3.amazonaws.com/0/6881/ab6a36f6-ad95-d816-4268-9c630b3428b9.png)|![Screenshot_1525876231.png](https://qiita-image-store.s3.amazonaws.com/0/6881/80e6ff25-81d8-a727-43e2-904d5610844c.png)|

---

## サイズを指定

- [CoordinatorLayout](https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout) に設定した幅が表示される [Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) の幅になります :straight_ruler:

---

### サンプル

- [CoordinatorLayout](https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout) の幅を画面幅の 10 % にする

#### 参考 :link:

- https://medium.com/google-developers/introducing-constraint-layout-1-1-d07fc02406bc

---

### コード

``` activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinatorLayout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintWidth_percent="0.1" />

    <android.support.design.widget.BottomNavigationView
        android:id="@id/bottomNavigationView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/navigation" />

</android.support.constraint.ConstraintLayout>
```

---

### 実行結果

| 例 ① | 例 ② |
|:------:|:-------:|
|![Screenshot_1525876506.png](https://qiita-image-store.s3.amazonaws.com/0/6881/f60afe8e-4149-2bf3-9277-a5dde6413c84.png)|![Screenshot_1525876512.png](https://qiita-image-store.s3.amazonaws.com/0/6881/2007596e-bf0b-456e-151d-be4291ddf5e2.png)|

---

# :three: 任意の位置 & 幅で

* [Material Design](https://material.io/) のガイドライン [Snackbars > Placement > Snackbars in wide layouts](https://material.io/design/components/snackbars.html#placement) によると、レイアウトの幅が広い場合、[Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) を「左揃え」または「中央揃え」にすることができます

| 左揃え | 中央揃え |
|:------:|:-------:|
|![snackbars-layout-desktop-do.png](https://qiita-image-store.s3.amazonaws.com/0/6881/5b6de080-8ebd-d046-fce7-069db8a433ac.png)|![snackbars-container-landscape-do-2.png](https://qiita-image-store.s3.amazonaws.com/0/6881/bee07314-7072-7f82-670a-d7b7b5eecc4d.png)|

---

## 実例

* Web 版 [Google+](https://plus.google.com/) で「フォロー」ボタン押下後に表示される [Snackbar](https://material.io/develop/web/components/snackbars/)

<img width="1163" alt="スクリーンショット.png" src="https://qiita-image-store.s3.amazonaws.com/0/6881/16bcf906-484b-b835-d41c-f0fc800b37d1.png">

---

### [YouTube](https://play.google.com/store/apps/details?id=com.google.android.youtube)

* Android タブレットでは右側（左側は高評価ボタンと重なり邪魔になるからと忖度 :thought_balloon: ）

![Screenshot_1526177863.png](https://qiita-image-store.s3.amazonaws.com/0/6881/f9c8980e-0309-7fcc-2411-4d1439c03315.png)

---

## サンプル

* [CoordinatorLayout](https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout) の位置と幅を調整して、[Snackbar](https://developer.android.com/reference/android/support/design/widget/Snackbar) を左寄せにします

---

### コード

``` activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinatorLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintStart_toStartOf="parent" />

    <android.support.design.widget.BottomNavigationView
        android:id="@id/bottomNavigationView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/navigation" />

</android.support.constraint.ConstraintLayout>
```

---

### 実行結果

![Screenshot_1525876646.png](https://qiita-image-store.s3.amazonaws.com/0/6881/2da33917-b152-84b9-cfb6-25758686447f.png)

---

# :end: