Android で塗りつぶした円の中に文字列を表示してみた件（TextView）

# 概要

`❶` の様に「塗りつぶした円の中央に数字を表示したい」という発注が来たので実現する方法について調査してみました :mag:

# [Shape Drawable](https://developer.android.com/guide/topics/resources/drawable-resource.html#Shape) を使用してみる

[TextView](https://developer.android.com/reference/android/widget/TextView.html) の background に `android:shape="oval"` と `android:shape="ring"` の [Shape Drawable](https://developer.android.com/guide/topics/resources/drawable-resource.html#Shape) を指定する方法を試してみます。

```oval_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@android:color/holo_blue_bright" />
</shape>
```

```ring_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="ring"
    android:useLevel="false">
    <solid android:color="@android:color/holo_blue_bright" />
</shape>
```

``` activity_circle_textview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <android.support.v4.widget.Space
        android:layout_width="10dp"
        android:layout_height="10dp" />

    <android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/oval_background"
        android:gravity="center"
        android:padding="4dp"
        android:text="め"
        android:textColor="@android:color/black" />

    <android.support.v4.widget.Space
        android:layout_width="10dp"
        android:layout_height="10dp" />

    <android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ring_background"
        android:gravity="center"
        android:padding="4dp"
        android:text="組"
        android:textColor="@android:color/black" />
</LinearLayout>
```

``` CircleTextViewActivity.java
package jp.co.package.example;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;

/**
 * 円の中に文字を表示する TextView のサンプル
 */
public class CircleTextViewActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_circle_textview);
    }
}
```

## 結果
![Screenshot_20160718-202313 2.png](https://qiita-image-store.s3.amazonaws.com/0/6881/cd3b0044-3f60-da43-092b-ef032e28d97e.png)

- `android:shape="oval"` の場合は塗りつぶしと `padding` の反映はされますが、サイズを `wrap_content` にしていると円ではなく楕円形になってしまいます。
- `android:shape="ring"` の場合は文字通り輪にはなりますが、中を塗りつぶすことはできませんでした。また上記の書き方では `padding` を反映することができませんでした :no_good:

# [EqualWidthHeightTextView](https://stackoverflow.com/a/35525977) を試してみる

Stack Overflow の[回答](https://stackoverflow.com/a/35525977)から引用してプロジェクト内にコピーしてみます。
※ [テキストが `10` 未満のときに `android:gravity="center"` で中央寄せにする場合は `android:inputType="number"` を追加する必要があります](https://stackoverflow.com/questions/25203501/android-creating-a-circular-textview/35525977#comment66653252_35525977)
※ [EqualWidthHeightTextView](https://stackoverflow.com/a/35525977) というクラス名ですが、SquareTextView という名前にしてもよいのではないかと思ったりします :thought_balloon: 

## 結果

円の中に文字列を表示することができました :ok_woman_tone1: （画像は省略）。

# [CircularTextView](https://stackoverflow.com/a/34685568) を試してみる

Stack Overflow の[回答](https://stackoverflow.com/a/34685568)から引用してプロジェクト内にコピーしてみます。

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <jp.co.package.example.CircularTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="4dp"
        android:text="俺"
        android:textColor="@android:color/white" />

    <!-- 省略 -->

</LinearLayout>
```

## 結果

`android:layout_width="wrap_content"` と
 `android:layout_height="wrap_content"`
にした状態で、円の中に文字を表示することができました :congratulations: 
しかし稀に円の描画が若干遅れるのが気になる…… :thinking:

![Screenshot_20160723-174623.png](https://qiita-image-store.s3.amazonaws.com/0/6881/f8df822f-f2d0-c2c1-c661-630d35c2d83d.png)

## 付加価値 :ideograph_advantage:

```java
circularTextView.setStrokeWidth(2);
circularTextView.setStrokeColor("#da721c");
```

とすることで Stroke の設定も可能です :o: 

![Screenshot_20160723-181113.png](https://qiita-image-store.s3.amazonaws.com/0/6881/29d5944a-59a3-a0b0-437c-13f4c60a5642.png)

## デメリット :warning:
遭遇した事例としては Android 7.0 ([Nougat](https://developer.android.com/about/versions/nougat/index.html)) の端末で :gear: 設定 > [高コントラストフォント] を ON にすると [CircularTextView](https://stackoverflow.com/a/34685568) が膨張するという事案が発生しました :rotating_light:

![download.gif](https://qiita-image-store.s3.amazonaws.com/0/6881/0ad1499a-612f-5828-86f1-70d686b5838a.gif)

# まとめ

個人的には [EqualWidthHeightTextView](https://stackoverflow.com/a/35525977) の使用をお勧めします :information_desk_person_tone1: