AlertDialog ばかり使うのではなく。。。

値を入力するダイアログで、コミットするボタン(positiveボタン)を制御したいと思った時、
AlertDialog で何とかしようなんて思わないことである。

Wheel と連動する EditText の入力ダイアログで、EditText の誤入力で
positiveボタンに抑制をかける。
ということがしたい。Toast エラーメッセージなどは表示しない仕様

カスタマイズの Dialog を作ったが、残念なことに完全な汎用性はない。

画面は、以下のとおり。

f:id:posturan:20160313195602p:plain


入力MAX を超えると、、、

f:id:posturan:20160313195555p:plain



Wheelは、http://code.google.com/p/android-wheel/ を使用する。

<?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:gravity="center_horizontal"
    android:orientation="vertical"
    android:background="@drawable/picker_background">
    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="25dp"
        android:layout_marginLeft="12dp"
        android:layout_marginRight="12dp"
        android:gravity="center_horizontal|center_vertical" >

        <kankan.wheel.widget.WheelView android:id="@+id/wheelValue"
            android:layout_height="120dp"
            android:layout_width="80dp" />

        <EditText
            android:id="@+id/editText1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:ems="4"
            android:inputType="number"
            android:maxEms="6"
            android:text="1" >
        </EditText>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <Button
            android:id="@+id/positiveButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1"
            android:text="OK" />
        <Button
            android:id="@+id/negativeButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1"
            android:text="cancel" />
    </LinearLayout>
</LinearLayout>

drawable/picker_background.xml の内容

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <gradient android:angle="90" android:startColor="#ff000000" android:endColor="#ff606060"/>
</shape>

BACKキーでキャンセルさせない、ダイアログ外側をタップしてキャンセルさせないように以下のとおりとする。Al

import kankan.wheel.widget.OnWheelChangedListener;
import kankan.wheel.widget.WheelView;
import kankan.wheel.widget.adapters.NumericWheelAdapter;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
/**
 * DecimalPicker.
 */

public class DecimalPicker extends Dialog{
   /**
    * Positiveボタン実行時の処理を約束。これをコンストラクタに渡す。
    *   min <= 入力値 <= max が約束されて呼ばれる
    */

   public interface PositiveListner{
      public void doPositive(int result);
   };

   private LayoutInflater layoutInflater;
   int min;
   int max;
   private int defaultValue;
   PositiveListner positiveListner;
   /**
    * Constructort
    * @param context Context
    * @param min 最小値
    * @param max 最大値
    * @param defaultValue 初期値
    * @param positiveListner Positiveボタン実行時の処理
    */

   public DecimalPicker(Context context,int min,int max,int defaultValue,PositiveListner positiveListner){
      super(context);
      layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      this.min = min;
      this.max = max;
      this.defaultValue = defaultValue;
      this.positiveListner = positiveListner;
   }
   @Override
   protected void onCreate(Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
      setContentView(layoutInflater.inflate(R.layout.decimal_picker,null));

      final int diff = min - 0;
      super.setCancelable(false);
      final EditText editText = (EditText)findViewById(R.id.editText1);
      editText.setText(Integer.toString(defaultValue));
      final WheelView pageWheel = (WheelView)findViewById(R.id.wheelValue);
      pageWheel.setViewAdapter(new NumericWheelAdapter(getContext(),min,max));
      pageWheel.setCurrentItem(defaultValue - diff);
      pageWheel.addChangingListener(new OnWheelChangedListener(){
         @Override
         public void onChanged(WheelView wheel,int oldValue,int newValue){
            editText.setText(Integer.toString(newValue+diff));
         }
      });

      final Button positiveButton = (Button)findViewById(R.id.positiveButton);
      editText.addTextChangedListener(new TextWatcher(){
         @Override
         public void onTextChanged(CharSequence s,int start,int before,int count){
         }
         @Override
         public void beforeTextChanged(CharSequence s,int start,int count,int after){
         }
         @Override
         public void afterTextChanged(Editable s){
            String str = s.toString();
            if (str.length() > 0){
               try{
                  int i = Integer.parseInt(str);
                  if (min <= i && i <= max){
                     positiveButton.setEnabled(true);
                     pageWheel.setCurrentItem(i - diff);

                  }else{
                     positiveButton.setEnabled(false);
                  }
               }catch(Exception e){
                  positiveButton.setEnabled(false);
               }
            }else{
               positiveButton.setEnabled(false);
            }
         }
      });
      positiveButton.setOnClickListener(new View.OnClickListener(){
         @Override
         public void onClick(View v){
            positiveListner.doPositive(pageWheel.getCurrentItem()+diff);
            dismiss();
         }
      });
      *1.setOnClickListener(new View.OnClickListener(){
         @Override
         public void onClick(View v){
            dismiss();
         }
      });
   }
   @Override
   public void setCancelable(boolean flag){
      super.setCancelable(false);
   }
}

呼び出しの例、、、

Button button = (Button)findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener(){
   @Override
   public void onClick(View v){
      Dialog dialog = new DecimalPicker(DecimalPickActivity.this, 1, 100, 21
      ,new DecimalPicker.PositiveListner(){
         @Override
         public void doPositive(int result){
            // 入力値 result に従った処理を行う。
         }
      });
      dialog.setTitle("テスト");
      dialog.show();
   }
});

*1:Button)findViewById(R.id.negativeButton