AndroidのGoogleサインインボタンをカスタムビューで作ってみる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/0df2898e-5843-b0f6-15ee-15aef2e45431.png)

```
  <io.github.yusukeiwaki.android.widget.GoogleSignInButton
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
  <io.github.yusukeiwaki.android.widget.GoogleSignInButton
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:color_style="dark"/>

  <io.github.yusukeiwaki.android.widget.GoogleSignInButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:color_style="light"/>
  <io.github.yusukeiwaki.android.widget.GoogleSignInButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:color_style="dark"/>
```


カスタムビューの練習としていいネタだったので作ってみただけです。

※ 多くの場合、 `com.google.android.gms.common.SignInButton` を使えば事足りるので、おそらく実用性はありませんｗ 単なる読み物としてお楽しみくださいませｗ

---

## とりあえずAppCompatButton継承

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  public GoogleSignInButton(Context context) {
    super(context);
  }

  public GoogleSignInButton(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public GoogleSignInButton(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/409fac59-692e-ae66-4ab7-e5087b5aa2ee.png)

当然、こうなります。寂しい。

## キャプションをSign in with Googleにする

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  public GoogleSignInButton(Context context) {
    super(context);
    initialize(context, null);
  }

  public GoogleSignInButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialize(context, attrs);
  }

  public GoogleSignInButton(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initialize(context, attrs);
  }

  private void initialize(Context context, @Nullable AttributeSet attrs) {
    setText("Sign in with Google");
  }
}
```

のように、何も考えずにやると、全部大文字になっちゃう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/e2ec7557-5143-0e95-7a61-01850b4d54d1.png)

### 全部大文字にはしない

`setSupportAllCaps` というメソッドがAppCompatButtonに生えてたのでこいつを使う。

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {

  // (コンストラクタは省略)

  private void initialize(Context context, @Nullable AttributeSet attrs) {
    setText("Sign in with Google");
    setSupportAllCaps(false);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/406d5457-7af3-536c-107d-adac7e1f81f3.png)

## 色指定をする

[Googleサインインボタンのスペック](https://developers.google.com/identity/branding-guidelines#sign-in-button)をみると

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/97f6a805-be22-0a14-39dc-91e0e363ed6f.png)

ということらしいので、XMLでdarkとlightを指定できるようにする。

```xml:res/values/google_sign_in_button_styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="GoogleSignInButton">
    <attr name="google_sign_in_button_color_style" format="enum">
      <enum name="light" value="0" />
      <enum name="dark" value="1" />
    </attr>
  </declare-styleable>
  <color name="google_sign_in_light_button_color">#FFFFFF</color>
  <color name="google_sign_in_light_button_text_color">#88000000</color>
  <color name="google_sign_in_dark_button_color">#4285F4</color>
  <color name="google_sign_in_dark_button_text_color">#FFFFFF</color>
</resources>
```

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  private static final int COLOR_STYLE_LIGHT = 0;
  private static final int COLOR_STYLE_DARK = 1;
  private int colorStyle;

  // (コンストラクタは省略)

  private void initialize(Context context, @Nullable AttributeSet attrs) {
    colorStyle = COLOR_STYLE_LIGHT;
    if (attrs != null) {
      TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GoogleSignInButton, 0,0);
      colorStyle = a.getInt(R.styleable.GoogleSignInButton_google_sign_in_button_color_style, colorStyle);
      a.recycle();
    }

    if (colorStyle == COLOR_STYLE_DARK) {
      setSupportBackgroundTintList(ContextCompat.getColorStateList(context, R.color.google_sign_in_dark_button_color));
      setTextColor(ContextCompat.getColor(context, R.color.google_sign_in_dark_button_text_color));
    } else {
      setSupportBackgroundTintList(ContextCompat.getColorStateList(context, R.color.google_sign_in_light_button_color));
      setTextColor(ContextCompat.getColor(context, R.color.google_sign_in_light_button_text_color));
    }

    setText("Sign in with Google");
    setSupportAllCaps(false);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/478098a1-e521-bc81-b6a4-15bf7b3d0c07.png)

だんだんそれっぽくなってきた。

## Gのアイコンを置く

これが最大に悩みポイント。[drawableLeft指定](http://y-anz-m.blogspot.jp/2010/09/android_6975.html)でやってみます。

まずは、SVGの G のアイコンをAndroid用に変換します。

```xml:res/drawable/ic_btn_google_sign_in.xml
<vector android:height="40dp" android:viewportHeight="46.0"
    android:viewportWidth="46.0" android:width="40dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FFFFFF"
        android:pathData="M5,3L41,3A2,2 0,0 1,43 5L43,41A2,2 0,0 1,41 43L5,43A2,2 0,0 1,3 41L3,5A2,2 0,0 1,5 3z"
        android:strokeColor="#00000000" android:strokeWidth="1"/>
    <path android:fillColor="#4285F4"
        android:pathData="M31.64,23.2C31.64,22.57 31.58,21.95 31.48,21.36L23,21.36L23,24.85L27.84,24.85C27.64,25.97 27,26.92 26.05,27.56L26.05,29.82L28.96,29.82C30.66,28.25 31.64,25.95 31.64,23.2L31.64,23.2Z"
        android:strokeColor="#00000000" android:strokeWidth="1"/>
    <path android:fillColor="#34A853"
        android:pathData="M23,32C25.43,32 27.47,31.19 28.96,29.82L26.05,27.56C25.24,28.1 24.21,28.42 23,28.42C20.66,28.42 18.67,26.84 17.96,24.71L14.96,24.71L14.96,27.04C16.44,29.98 19.48,32 23,32L23,32Z"
        android:strokeColor="#00000000" android:strokeWidth="1"/>
    <path android:fillColor="#FBBC05"
        android:pathData="M17.96,24.71C17.78,24.17 17.68,23.59 17.68,23C17.68,22.41 17.78,21.83 17.96,21.29L17.96,18.96L14.96,18.96C14.35,20.17 14,21.55 14,23C14,24.45 14.35,25.83 14.96,27.04L17.96,24.71L17.96,24.71Z"
        android:strokeColor="#00000000" android:strokeWidth="1"/>
    <path android:fillColor="#EA4335"
        android:pathData="M23,17.58C24.32,17.58 25.51,18.03 26.44,18.93L29.02,16.34C27.46,14.89 25.43,14 23,14C19.48,14 16.44,16.02 14.96,18.96L17.96,21.29C18.67,19.16 20.66,17.58 23,17.58L23,17.58Z"
        android:strokeColor="#00000000" android:strokeWidth="1"/>
</vector>
```

それを、 `setCompoundDrawablesWithIntrinsicBounds` を使ってdrawableLeftに指定します。

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  private static final int COLOR_STYLE_LIGHT = 0;
  private static final int COLOR_STYLE_DARK = 1;
  private int colorStyle;

  // (コンストラクタは省略)

  private void initialize(Context context, @Nullable AttributeSet attrs) {

    // (色指定・テキスト設定は省略)

    Drawable leftDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_btn_google_light_filled);
    setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/57e4591a-c984-7013-3a4c-b6b0a1b4efd6.png)

たしかに左側に画像は設定された。でも画像とテキストの間のスペースや、高さが変。

[Googleサインインボタンのスペック](https://developers.google.com/identity/branding-guidelines#sign-in-button)を改めてみると

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/585a0de7-c050-0dc4-1cab-de09f4c7a389.png)

ということで、

* 高さは40dp
* 左右は8dpあけるんだけど、 G のアイコンに含まれるパディングを考慮して8dpを設定しないといけない
* GのアイコンとSign in with Googleの間には24dpあける

あたりを対応する必要がある。

### 高さを40dpにする

AndroidのButtonは、デフォルトでminWidth, minHeight指定がそこそこ大きめに設定されているので、それを上書きする。

```xml:res/values/google_sign_in_button_styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

  <!-- (色指定・テキスト設定は省略) -->

  <dimen name="google_sign_in_button_height">40dp</dimen>
</resources>
```

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  private static final int COLOR_STYLE_LIGHT = 0;
  private static final int COLOR_STYLE_DARK = 1;
  private int colorStyle;

  // (コンストラクタは省略)

  private void initialize(Context context, @Nullable AttributeSet attrs) {

    // (色指定・テキスト設定は省略)

    Drawable leftDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_btn_google_light_filled);
    setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

    int height = getResources().getDimensionPixelSize(R.dimen.google_sign_in_button_height);
    setMinimumHeight(height);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/197f9970-2f81-3ba5-7fe7-dfcf39daeb5e.png)

あれ、かわらない。

#### 上下のpaddingは0にする

```
    Log.d("GoogleSIgnInButton",
        String.format("padding: left=%d top=%d right=%d bottom=%d",
            getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom()));
```

みたいなログを仕込んでみるとわかるように、Android標準のボタンには

```
12-10 00:58:12.206 D/GoogleSIgnInButton( 8544): padding: left=24 top=20 right=24 bottom=20
```

上下左右に微妙なpaddingが指定されています。

が、少なくとも上下のpaddingはいらなさそうなので消しちゃいましょう。

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  private static final int COLOR_STYLE_LIGHT = 0;
  private static final int COLOR_STYLE_DARK = 1;
  private int colorStyle;

  // (コンストラクタは省略)

  private void initialize(Context context, @Nullable AttributeSet attrs) {

    // (色指定・テキスト設定は省略)

    Drawable leftDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_btn_google_light_filled);
    setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

    int height = getResources().getDimensionPixelSize(R.dimen.google_sign_in_button_height);
    setMinimumHeight(height);

    setPadding(getPaddingLeft(), 0, getPaddingRight(), 0);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/16357e67-aa3e-26fc-9006-2fc073a96d41.png)

だいぶそれっぽくなってきた。

## G の画像の位置を調整する

Gの左側に8dp空いてるのを切り詰めて、Gとテキストの間に8dp追加すれば良さそうです。


```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  private static final int COLOR_STYLE_LIGHT = 0;
  private static final int COLOR_STYLE_DARK = 1;
  private int colorStyle;

  // (コンストラクタは省略)

  private void initialize(Context context, @Nullable AttributeSet attrs) {

    // (色指定・テキスト設定は省略)

    Drawable leftDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_btn_google_light_filled);
    setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

    int height = getResources().getDimensionPixelSize(R.dimen.google_sign_in_button_height);
    setMinimumHeight(height);

    int originalPaddingLeft = getPaddingLeft();
    setPadding(0, 0, getPaddingRight(), 0);
    setCompoundDrawablePadding(originalPaddingLeft);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/aab7216f-a4c1-d2ce-6220-8a55efc81ec2.png)

うーむ、どうやら 0dpでは左に行き過ぎちゃうらしい・・・。

### paddingLeftを2dpにする

微調整の結果、2dpくらいにするとちょうどになりました。

```xml:res/values/google_sign_in_button_styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

  <!-- (色指定・テキスト設定は省略) -->

  <dimen name="google_sign_in_button_height">40dp</dimen>
  <dimen name="google_sign_in_button_padding_left">2dp</dimen>
</resources>
```

```java:GoogleSignInButton.java
public class GoogleSignInButton extends AppCompatButton {
  private static final int COLOR_STYLE_LIGHT = 0;
  private static final int COLOR_STYLE_DARK = 1;
  private int colorStyle;

  // (コンストラクタは省略)

  private void initialize(Context context, @Nullable AttributeSet attrs) {

    // (色指定・テキスト設定は省略)

    Drawable leftDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_btn_google_light_filled);
    setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

    int height = getResources().getDimensionPixelSize(R.dimen.google_sign_in_button_height);
    setMinimumHeight(height);

    int paddingLeft = getResources().getDimensionPixelSize(R.dimen.google_sign_in_button_padding_left);
    int originalPaddingLeft = getPaddingLeft();
    setPadding(paddingLeft, 0, getPaddingRight(), 0);
    setCompoundDrawablePadding(originalPaddingLeft);
  }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74571/e4e72631-d9c5-acb5-969f-4b65dfa8baed.png)

## まとめ

なんとなく練習台としてよさそうだったのでGoogleログインボタンを作ってみただけです。

Googleログインには `com.google.android.gms.common.SignInButton` を使いましょう。