Android の Spinner を簡単に使う

#はじめに
数年ぶりに Android のアプリを書こうとしたら、Android Studio は（以前は Eclipse でしたが）随分高機能化したようでしたが、UI 開発周りの IDE での補助が 25 年以上前の MFC にも劣るように感じられました（個人の感想です）。
Android2.x 時代から私が（作って）使っているユーティリティクラスのようなコードのデザインパターンを検索しても見かけなかったので（よく探せばあるかもしれませんが）、ここでは Spinner のユーティリティクラスを紹介します。

#Spinnerとは？
Win32 のコンボボックス（ドロップダウンリスト）に相当するUIです。
https://developer.android.com/guide/topics/ui/controls/spinner?hl=ja
![spinner.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285025/a6e9baf8-75ea-a03b-66f2-fa72e5c073dc.png)

#使い方
クラスのソースコードは最後に付加しておきますので、まずは使い方を説明します。
まずは以下のような準備をします。

```
private UIDialog.SimpleSpinner  m_smplSpin ;

// 表示項目
String[] spinNameArray = { "リスト1", "リスト2", "リスト3", ... } ;

// 対象のスピナー
Spinner spinner = view.findViewById( R.id.対象のスピナー) ;

// 準備
int numSpinner = 1 ;  // ← "リスト2" を初めに選択する
m_smplSpin = new UIDialog.SimpleSpinner
	( spinner, numSpinner, spinNameArray , null) ;
```

spinner は findViewById でも、binding でも、何か好きな方法で取得してください。
そして、値を取得したいタイミングで

```
int indexSelected = m_smplSpin.getSelectionIndex() ;
```

を呼び出すと indexSelected に選択された番号（0～）が取得できます。
選択されていないときは -1 になります。

もし、番号が 0 からの連番でない場合には

```
int[] spinNumArray = { 0, -1, 1, ... } ;
int numSpinner = 1 ;  // ← "リスト3" を初めに選択する
m_smplSpin = new UIDialog.SimpleSpinner
	( spinner, numSpinner, spinNameArray, spinNumArray ) ;
```

のように、int[] を渡しておくといい感じにやってくれて、結果は同様に getSelectionIndex 又は、

```
int numSelected = m_smplSpin.getSelectionNum( -2 ) ;
```

で取得します。引数は選択されていないときに返却する値を指定します。
getSelectionIndex は 0～ の連番、getSelectionNum は対応する任意の値を返します。

選択が変更されたときに処理をしたい場合には結局リスナを派生することになりますが、以下のようにします。

```
m_smplSpin = new UIDialog.SimpleSpinner
	( spinner, numSpinner, spinNameArray, spinNumArray
		new UIDialog.SimpleSpinnerListener()
		{
			@Override
			public void onSelected( SimpleSpinner spinner, int index )
			{
				// 何かの処理...
			}
		}
} ;
```

これでも一応、値が連番でないときや、選択されていない状態を index に -1 で受け取れるなど、コードの簡略化が出来るなどの利点は一応あります。

大抵の UI 要素はシンプルなデフォルトの挙動で十分なことが多いと思いますのでコードを簡略化できます。


#ソース

以下がソースです。
UIDialog と言うクラスの中に入っていますが外に出しても問題無いと思います。
（実際には他にもいろいろ入っていますが、ここでは省略して Spinner 部分だけ記載します）

```
public class	UIDialog
{
	// スピナー通知
	public interface SimpleSpinnerListener
	{
		public abstract void onSelected( SimpleSpinner spinner, int index ) ;
	}

	// スピナーアイテム・ユーティリティ
	public static class SimpleSpinner   implements AdapterView.OnItemSelectedListener
	{
		private Spinner                 m_spinner = null ;
		private int                     m_selection = 0 ;
		private String[]                m_aTextArray = null ;
		private int[]                   m_aNumArray = null ;
		private SimpleSpinnerListener   m_listener = null ;

		public SimpleSpinner
			( Spinner spinner, int iFirstNum, String[] aTextArray, int[] aNumArray )
		{
			m_aTextArray = aTextArray ;
			m_aNumArray = aNumArray ;
			setupSpinner
				( spinner, iFirstNum,
					android.R.layout.simple_spinner_item,
					android.R.layout.simple_spinner_dropdown_item ) ;
		}
		public SimpleSpinner
			( Spinner spinner, int iFirstNum,
				String[] aTextArray, int[] aNumArray, SimpleSpinnerListener listener )
		{
			m_aTextArray = aTextArray ;
			m_aNumArray = aNumArray ;
			m_listener = listener ;
			setupSpinner
				( spinner, iFirstNum,
					android.R.layout.simple_spinner_item,
					android.R.layout.simple_spinner_dropdown_item ) ;
		}
		public SimpleSpinner
			( Spinner spinner, int iFirstNum,
			  String[] aTextArray, int[] aNumArray,
			  int resSpinnerItem, SimpleSpinnerListener listener )
		{
			m_aTextArray = aTextArray ;
			m_aNumArray = aNumArray ;
			m_listener = listener ;
			setupSpinner
				( spinner, iFirstNum, resSpinnerItem,
						android.R.layout.simple_spinner_dropdown_item ) ;
		}
		public SimpleSpinner
			( Spinner spinner, int iFirstNum,
			  String[] aTextArray, int[] aNumArray,
			  int resSpinnerItem, int resDropdownItem,
			  SimpleSpinnerListener listener )
		{
			m_aTextArray = aTextArray ;
			m_aNumArray = aNumArray ;
			m_listener = listener ;
			setupSpinner( spinner, iFirstNum, resSpinnerItem, resDropdownItem ) ;
		}

		public void setupSpinner
			( Spinner spinner, int iFirstNum,
			  int resSpinnerItem, int resDropdownItem )
		{
			m_spinner = spinner ;
			m_selection = numToSelection( iFirstNum ) ;
			ArrayAdapter<String>
				adpStyleList = new ArrayAdapter
					( EntisGLS.getMainActivity(), resSpinnerItem, m_aTextArray ) ;
			adpStyleList.setDropDownViewResource( resDropdownItem ) ;
			spinner.setAdapter( adpStyleList ) ;
			if ( (m_selection >= 0) && (m_selection < m_aTextArray.length) )
			{
				spinner.setSelection( m_selection ) ;
			}
			spinner.setOnItemSelectedListener( this ) ;
		}

		protected int numToSelection( int num )
		{
			if ( m_aNumArray == null )
			{
				return  num ;
			}
			for ( int i = 0; i < m_aNumArray.length; i ++ )
			{
				if ( m_aNumArray[i] == num )
				{
					return  i ;
				}
			}
			return  -1 ;
		}

		public Spinner getSpinner()
		{
			return  m_spinner ;
		}

		public int getSelectionIndex()
		{
			return  m_selection ;
		}
		public int getSelectionNum( int ifNonSelected )
		{
			if ( m_aNumArray == null )
			{
				return  m_selection ;
			}
			if ( m_selection >= 0 )
			{
				return  m_aNumArray[m_selection] ;
			}
			return  ifNonSelected ;
		}

		@Override
		public void onItemSelected
			( AdapterView<?> parent, View view, int position, long id )
		{
			if ( (position >= 0) && (position < m_aTextArray.length) )
			{
				m_selection = position ;
				if ( m_listener != null )
				{
					m_listener.onSelected( this, m_selection ) ;
				}
			}
		}

		@Override
		public void onNothingSelected (AdapterView<?> parent)
		{
			m_selection = -1 ;
			if ( m_listener != null )
			{
				m_listener.onSelected( this, m_selection ) ;
			}
		}
	}
}
```