NumberPickerをカスタムして使う

この記事は[WHITEPLUS Advent Calendar 2016](http://qiita.com/advent-calendar/2016/whiteplus) 7日目になります。

こんにちは。株式会社ホワイトプラス、インターン（エンジニア）の @ksbababa です。

ホワイトプラスではAndroidアプリ開発や技術調査などに関わらせていただいてます。

#AndroidでPickerViewのようなもの
iOSではユーザーに選択肢を提示するコントロールにPickerViewがあります。
AndroidではSpinnerを用いることが多いかと思いますが、表示する内容やデザインによってiOSのPickerViewのようなものが欲しいときがあります。

##NumberPicker
無いものは作る精神で独自Viewを定義するのもいいですが、AndroidにはiOSのPickerViewに似たNumberPickerというコントロールがあります。
コントロールの名前からは数値専用Pickerのような印象を受けますが、簡単に文字列を表示させることができます。

```java
String[] data = {"hoge", "fuga", "piyo"};
NumberPicker picker = (NumberPicker)findViewById(R.id.SamplePicker);
picker.setDisplayedValues(data);
```

####実行結果
<img width="69" alt="Screen Shot 2016-12-07 at 07.02.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/101042/6474359e-8f50-81d2-5487-cf5ae6391070.png">

#### 注意点
このままだとsetDisplayedValuesを叩いたり、要素数(maxValue等)の変更をしたりすると落ちてしまうのですが、最初にsetDisplayedValuesにnullを入れておけば解決するはずです。

```java
picker.setDisplayedValues(null);
```

##NumberPickerのStyleを変更する
コードで変更しても良いですが、再利用するならばNumberPickerを継承してクラスを定義するのが楽だと思います。
addView関数をoverrideしてテキストの色を変えてみます。

```java
    @Override
    public void addView(View child, ...略) {
        super.addView(child);
        updateView(child);
    }

    private void updateView(View view) {
        if(view instanceof EditText){
            ((EditText) view).setTextColor(Color.RED);
        }
    }
```

###実行結果
<img width="63" alt="Screen Shot 2016-12-07 at 08.04.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/101042/4abc1cc9-93a6-925a-12a7-11e19311f283.png">

##データに応じて表示を変える
これだけではあまり面白くないので、データに応じて表示を変えてみます。
例えば、選択肢の一部が選択不可能であることを伝えたい場合を考えます。
選択している値に応じて表示を変えるのでpickerのsetOnValueChangedListenerに以下のような関数を設定します。

```java

    private void setPickerStyles() {
        final int count = picker.getChildCount();
        for (int i = 0; i < count; i++) { // テキスト部を探す
            View child = picker.getChildAt(i);
            if (child instanceof EditText) {
                EditText et = (EditText) child;
                try {
                    Field selectorWheelPaintField = picker.getClass().getSuperclass().getDeclaredField("mSelectorWheelPaint");
                    selectorWheelPaintField.setAccessible(true);
                    Paint pickerPaint = (Paint)selectorWheelPaintField.get(picker);
                    if (et.getText().toString().equals("fuga")) {
                        pickerPaint.setColor(Color.GRAY); 　// 選択不可
                    } else {
                        pickerPaint.setColor(Color.BLACK); 　// 選択可
                    }
                    picker.invalidate();  // 再描画
                } catch (NoSuchFieldException e) {
                    // 例外処理
                    Log.d("NoSuchFieldException", e.toString());
                } catch (IllegalAccessException e) {
                    // 例外処理
                    Log.d("IllegalAccessException", e.toString());
                }
            }
        }
    }

```

####実行結果
<img width="63" alt="Screen Shot 2016-12-07 at 07.47.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/101042/cf18beb3-24ae-c0d6-9bf8-5d752b27d5a9.png">

灰色にしただけでdisable感が出たのでは無いでしょうか（？）

#まとめ
簡単な内容でしたが、意外と情報が無いような気がしたのでこの機会にまとめてみました。
誰かの助けになれば幸いです。


#ホワイトプラスではエンジニアを募集しています
ホワイトプラスでは、[新しい技術にどんどん挑戦したい！という技術で事業に貢献したいエンジニアを募集](https://www.wantedly.com/projects/69257)しております。