前回の続き

SDKで用意されているEditTextPreferenceなどでは機能不足な場合もあります。その場合は、Preference、もしくはPreferenceのサブクラスを継承してカスタムPreferenceを作ると良いでしょう。

EditTextPreferenceに最小文字数を指定できるようにする

EditTextPreferenceでは最大文字数は、android:maxLengthで指定出来ますが、最小文字数は指定出来ません。実現するためにEditTextPreferenceのサブクラスを作ります。

サンプル: https://github.com/stack3/AndroidPreferenceSamples

サンプルを起動してCustomPreferenceを選択すると以下の画面が表示されます。

01

ユーザー名を選択して、入力文字を3文字未満にしてみてください。するとOKボタンが押せない状態(Disabled)になります。

02-1

カスタムクラス用の属性

res/values/attrs.xmlで以下のようにminLengthという属性(Attribute)を定義しています。

<?xml version="1.0" encoding="utf-8"?>
<resources>
  〜〜中略〜〜
  <declare-styleable name="CustomEditTextPreference">
    <attr name="minLength" format="integer" />
  </declare-styleable>
  〜〜中略〜〜
</resources>

formatはstring,floatなどが使えますが、今回は整数値なのでintegerとしています。

設定画面のレイアウトXML

res/xml/custom_preference_screen_sample.xmlで以下のようにEditTextPreferenceのサブクラス、CustomEditTextPreferenceを配置しています。

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res/net.stack3.preferencesamples">

  <net.stack3.preferencesamples.custompreference.CustomEditTextPreference
    android:key="username"
    android:title="@string/username"
    android:dialogTitle="@string/username"
    android:maxLength="20"
    app:minLength="3" />

〜〜中略〜〜

</PreferenceScreen>

CustomEditTextPreferenceクラスの説明の前に、ここで指定されているapp:minLengthという属性について説明します。

xmlns:app="http://schemas.android.com/apk/res/net.stack3.preferencesamples">

とありますが、これでattrs.xmlで宣言した属性が使えるようになります。

net.stack3.preferencesamplesの部分はアプリのパッケージ名となります。よってアプリごとに異なります。

また、xmlns:appのappの部分は任意の文字列で構いません。

xmlns:{namespaceのエイリアス}="http://schemas.android.com/apk/res/{アプリのパッケージ名}">

app:minLength属性を3とすることで最初文字数を3としています。

CustomEditTextPreferenceクラス

EditTextPreferenceクラスを継承してnet.stack3.preferencesamples.custompreference.CustomEditTextPreferenceクラスを作っています。

public class CustomEditTextPreference extends EditTextPreference {

minLength属性をsetupメソッドで読んでいます。

// 念のためデフォルト値で初期化しておく
private int minLength = Integer.MAX_VALUE;

〜〜中略〜〜

private void setup(Context context, AttributeSet attrs) {
    TypedArray a = context.obtainStyledAttributes(attrs,
  R.styleable.CustomEditTextPreference, 0, 0);
    minLength = a.getInt(R.styleable.CustomEditTextPreference_minLength, Integer.MAX_VALUE);
    a.recycle();
}

setupメソッドは各種コンストラクタで呼び出します。

public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setup(context, attrs);
}

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

updateOKButtonメソッドで入力文字の長さがminLength未満ならOKボタンを使用不可にします。

private void updateOKButton(int textLength) {
    Dialog dialog = getDialog();
    if (dialog != null) {
        //
        // Disable OK button if the edit text was lesser than minLength. 
        //
        Button okButton = (Button)dialog.findViewById(android.R.id.button1);
        okButton.setEnabled(textLength >= minLength);
    }
}

以下のメソッドで文字列編集用のEditTextが得られるので、文字が変更された時のイベントを受け取るようにListenerを設定します。

@Override
protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
    super.onAddEditTextToDialogView(dialogView, editText);
    editText.addTextChangedListener(textChangeListener);
}

文字変更のListener。onTextChangedでupdateOKButtonを呼びます。これで文字変更されるたびに長さをチェックしてOKボタンの使用可能状態を適切にします。

private TextWatcher textChangeListener = new TextWatcher() {
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        updateOKButton(s.length());
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
};

文字が変更された時だけでなく、文字入力ダイアログが表示された時も、文字列の長さに応じてOKボタンの状態を適切にする必要があります。よってshowDialogメソッドでもupdateOKButtonを呼びます。

@Override
protected void showDialog(Bundle state) {
    super.showDialog(state);
    updateOKButton(getText().length());
}

EditTextPreference(実際は親クラスのDialogPreference)には、onCreateDialogView,onBindDialogViewなどのメソッドがありますが、これらの中ではgetDialogしてもDialogオブジェクトを得られないので注意です。showDialogで取得するのが無難だと思います。

CustomPreferenceSampleActivity

Activityの実装は前回の記事のPreferenceScreenSampleActivityと似たようなものなので割愛します。

その4へ続く