Form validation library for Android applications.
APACHE-2.0 License
AndroidFormEnhancerは、Androidアプリケーションで入力フォームを簡単に実装するためのライブラリです。 アノテーションを利用して、入力フォームに関する定義を簡潔に記述することができ、 ActivityやFragmentの中に含まれる画面との値のやり取りや入力チェックのコードを削減することができます。
UI部品の入力値がシンプルなPOJOクラスで処理可能 入力値検証がアノテーションで実装可能 多数の入力値検証パターンが利用できカスタマイズも可能 入力エラーメッセージは簡単に取得できダイアログ表示も可能 エラーメッセージ、アイコン、..といったものもカスタマイズ可能 APIレベル 8 から 19 までをサポート
ライブラリを使用したサンプルアプリケーションは、androidformenhancer-samples
フォルダに含まれています。
Google Playからダウンロードしてお試しいただけます。
repositories {
mavenCentral()
}
dependencies {
compile 'com.github.ksoichiro:androidformenhancer:1.1.0@aar'
}
androidformenhancerフォルダがライブラリ本体です。 EclipseでAndroid Library Projectとして取り込んでください。
入力フォーム用のPOJOクラスを作成し、アノテーションでフォームの仕様を定義します。
public class DefaultForm {
@Widget(id = R.id.textfield_name)
@Required
public String name;
@Widget(id = R.id.textfield_age, validateAfter = R.id.textfield_name)
@IntType
public String age;
}
入力値を文字列以外のエンティティとして使用したい場合は、同名のフィールドを持つエンティティクラスを用意します。
public class DefaultEntity {
public String name;
public int age;
}
ActivityやFragmentに下記のようなコードを書いて、画面から入力値を取り出すところから入力チェック、型変換を行ないます。
ValidationResult result = new FormHelper(DefaultForm.class, this).validate();
if (result.hasError()) {
// エラーメッセージを表示します
Toast.makeText(this, result.getAllSerializedErrors(), Toast.LENGTH_SHORT).show();
} else {
// entityは入力チェック・型変換の済んだオブジェクトです
DefaultEntity entity = helper.create(DefaultEntity.class);
}
もしフォーカスが外れたタイミングで入力チェックしたい場合は、次のように書くだけです。
new FormHelper(DefaultForm.class, this).setOnFocusOutValidation();
ただし、これはテキストのフィールドだけに有効な方法です。
android.app.Activity
以外のクラスを使う場合は、ActivityFormHelper
を別のクラスに置き換えてください。
android.support.v4.app.FragmentActivity
を使う場合は、FragmentActivityFormHelper
に置き換えます。android.support.v4.app.Fragment
を使う場合は、SupportFragmentFormHelper
に置き換えます。レイアウトから入力値を取得するには、まずFormクラスを作成します。
Formクラスはpublicなフィールドを持つだけの単なるPOJOクラスです。
全てのフィールドはpublicで、String
かjava.util.List<String>
型である必要があります。
public class DefaultForm {
public String name;
}
各フィールドは、android.widget.EditText
のようなウィジェットと関連付ける必要がります。
ウィジェットとの関連付けをするには、特別なアノテーションをフィールドに付与します。
<EditText>
タグを使う場合は、@Widget
をFormクラスのフィールドに付与します。
例えば、res/layout/some_layout.xml
の一部が以下の通りだとします。
<EditText
android:id="@+id/textfield_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
この場合、Formクラスの定義は次のようにします。
public class DefaultForm {
@Widget(id = R.id.textfield_name)
public String name;
}
<RadioGroup>
タグや<RadioButton>
を使い、いずれかのラジオボタンが選択されていることを
検証したい場合は、@Widget
と@WidgetValue
のアノテーションをFormクラスのフィールドに付与します。
例えば、res/layout/some_layout.xml
の一部が以下の通りだとします。
<RadioGroup
android:id="@+id/rg_gender"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:id="@+id/rb_male"
android:text="男性"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RadioButton
android:id="@+id/rb_female"
android:text="女性"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RadioGroup>
この場合、Formクラスの定義は次のようにします。
public class DefaultForm {
@Widget(id = R.id.rg_gender,
values = {
@WidgetValue(id = R.id.rb_male, value = "M"),
@WidgetValue(id = R.id.rb_female, value = "F"),
})
public String gender;
}
もし"男性"のラジオボタンを選択すれば、DefaultForm#gender
の値は"M"になります。
<CheckBox>
タグを使用し、少なくとも1つ以上のチェックボックスがチェックされている
ことを検証したい場合は、@Widget
と@WidgetValue
アノテーションを
Formクラスのフィールドに付与します。
例えば、res/layout/some_layout.xml
の一部が以下の通りだとします。
<LinearLayout
android:id="@+id/cbg_sns"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<CheckBox
android:id="@+id/cb_facebook"
android:text="Facebook"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/cb_googleplus"
android:text="Google+"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/cb_twitter"
android:text="Twitter"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
この場合、Formクラスの定義は次のようにします。
public class DefaultForm {
@Required(atLeast = 1)
@Widget(id = R.id.cbg_sns,
values = {
@WidgetValue(id = R.id.cb_facebook, value = "FB"),
@WidgetValue(id = R.id.cb_googleplus, value = "GP"),
@WidgetValue(id = R.id.cb_twitter, value = "TW")
})
public List<String> sns;
}
もし"Facebook"と"Google+"のチェックボックスを選択したならば、
DefaultForm#sns
の値は"FB"と"GP"の2つの要素を持つList<String>
になります。
@Widget
は、単に同じ種類のCheckBox
をグループ化するためだけに使用しています。
この例にあるLinearLayout
だけでなく、他のViewGroup
のサブクラスである
RelativeLayout
なども@Widget
と関連付けられることに注意してください。
<Spinner>
タグを使う場合は、@Widget
アノテーションをFormクラスのフィールドに付与します。
例えば、res/layout/some_layout.xml
の一部が以下の通りだとします。
<Spinner
android:id="@+id/spn_credit_card_type"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
この場合、Formクラスの定義は次のようにします。
public class DefaultForm {
@Widget(id = R.id.spn_credit_card_type, Widget.Type.SPINNER)
public String creditCardType;
}
もし、先頭の要素を"選択してください"のようなダミー文字列として使いたい場合は、
@Required
アノテーションをフィールドに追加し、Required#otherThanHead
をtrue
に設定します。
これにより、先頭の要素以外が選択されているかどうかを検証することができます。
以下の検証クラスが利用できます。
null
や空文字列でないことを検証します。@Required
アノテーションを付与されている必要があります。@When
を併せて使います。
public class CustomRequiredWhenForm {
@Widget(id = R.id.spn_reason, nameResId = R.string.form_custom_required_when_reason)
public String reason;
@Widget(id = R.id.textfield_reason_other, nameResId = R.string.form_custom_required_when_reason_other,
validateAfter = R.id.spn_reason)
@Required(when = {
@When(id = R.id.spn_reason, equalsTo = "2")
})
public String reasonOther;
}
もしユーザがR.id.spn_reason
のSpinnerから3番目の選択肢を選び、R.id.textfield_reason_other
のテキストフィールドに入力しなかった場合、@IntType
アノテーションを付与されている必要があります。@FloatType
アノテーションを付与されている必要があります。@MaxValue
アノテーションを付与されている必要があります。@MinValue
アノテーションを付与されている必要があります。IntRange#min()
、最大値はIntRange#max()
で指定します。@IntRange
アノテーションを付与されている必要があります。@Digits
アノテーションを付与されている必要があります。@Alphabet
アノテーションを付与されている必要があります。Alphabet#allowSpace()
をtrue
に設定します。@AlphaNum
アノテーションを付与されている必要があります。AlphaNum#allowSpace()
をtrue
に設定します。@Hiragana
アノテーションを付与されている必要があります。@Katakana
アノテーションを付与されている必要があります。@Singlebyte
アノテーションを付与されている必要があります。@Multibyte
アノテーションを付与されている必要があります。@Length
アノテーションを付与されている必要があります。@MaxLength
アノテーションを付与されている必要があります。@NumOfDigits
アノテーションを付与されている必要があります。NumOfDigits#value()
で指定する桁数(文字数)と一致していなくても、@MaxNumOfDigits
アノテーションを付与されている必要があります。MaxNumOfDigits#value()
で指定する桁数(文字数)を超えていても、@DatePattern
アノテーションを付与されている必要があります。java.text.DateFormat.SHORT
が使用されます。これはロケールにより変化します。DatePattern#value()
を使用してください。@PastDate
アノテーションを付与されている必要があります。java.text.DateFormat.SHORT
が使用されます。これはロケールにより変化します。PastDate#value()
を使用してください。PastDate#allowToday
をtrue
に設定してください。@Email
アノテーションを付与されている必要があります。^[\\w-]+(\\.[\\w-]+)*@([\\w][\\w-]*\\.)+[\\w][\\w-]*$
afeValidatorDefinitions
とafeCustomEmailPattern
を使用してstyleに形式を定義してください。@Regex
アノテーションを付与されている必要があります。Regex#value()
で指定します。各項目の検証順序は、Widget#validateAfter
を使用して定義します。
例えば、以下のように定義した場合は、name
、age
の順番に検証されます。
画面の表示順とは異なることに注意してください。
public class DefaultForm {
@Widget(id = R.id.textfield_name)
@Required
public String name;
@Widget(id = R.id.textfield_age, validateAfter = R.id.textfield_name)
@IntType
public String age;
}
ライブラリの挙動やメッセージは、以下のようにカスタマイズすることができます。
停止ポリシー
検証クラスがエラーを検出したときに、そのまま続行するか停止するかを制御します。 例えば、エラーを検出しても全項目を検証し、全てのエラーを表示したい場合は 以下のようにテーマを定義します。
<style name="YourTheme">
<item name="afeValidatorDefinitions">@style/YourValidatorDefinitions</item>
</style>
<style name="YourValidatorDefinitions" parent="@style/AfeDefaultValidators">
<item name="afeStopPolicy">continueAll</item>
</style>
利用可能な検証クラス
標準で利用可能な検証クラスは、有効/無効を切り替えることができ、 独自の検証クラスを追加することもできます。 例えば、RequiredValidatorだけを有効にしたい場合は、以下のようにテーマを定義します。
<string-array name="your_standard_validators">
<item>com.androidformenhancer.validator.RequiredValidator</item>
</string>
<style name="YourTheme">
<item name="afeValidatorDefinitions">@style/YourValidatorDefinitions</item>
</style>
<style name="YourValidatorDefinitions" parent="@style/AfeDefaultValidators">
<item name="afeStandardValidators">@array/your_standard_validators</item>
</style>
検証エラーメッセージ
検証エラーメッセージは上書きすることができます。 例えば、RequiredValidatorのエラーメッセージを上書きしたい場合は 以下のようにテーマを定義します。
<string name="custom_msg_validation_required">%1$sは絶対に入力してください!</string>
<style name="YourTheme">
<item name="afeValidatorMessages">@style/YourValidatorMessages</item>
</style>
<style name="YourValidatorMessages">
<item name="afeErrorRequired">@string/custom_msg_validation_required</item>
</style>
エラーメッセージに含める項目名は、デフォルトではFormクラスに定義するフィールド名が使用されます。
この項目名を変更したい場合は、アノテーションのnameResId
属性を使用してください。
例えば、以下のようにフィールドを定義します。
@Widget(id = R.id.textfield_name)
@Required
public String firstName;
この場合、エラーメッセージは「firstNameは必ず入力してください」となります。 項目名をカスタマイズする場合、Formは以下のように定義します。
@Widget(id = R.id.textfield_name, nameResId = R.string.first_name)
@Required
public String firstName;
もしくは下記の形式です。
@Widget(id = R.id.textfield_name)
@Required(nameResId = R.string.first_name)
public String firstName;
strings.xmlを次のように記述した場合
<string name="first_name">お名前(名)</string>
エラーメッセージは「お名前(名)は必ず入力してください」となります。
エラーアイコン
入力チェックエラー時に表示されるアイコンは次のように変更することができます。
<style name="YourTheme">
<item name="afeValidatorDefinitions">@style/YourValidatorDefinitions</item>
</style>
<style name="YourValidatorDefinitions" parent="@style/AfeDefaultValidators">
<item name="afeValidationIconError">@drawable/your_icon_error</item>
<item name="afeValidationIconOk">@drawable/your_icon_ok</item>
</style>
このプロジェクトにはGradleラッパーが含まれており、このプロジェクトの開発で使用されています。 安定したビルドのために、ライブラリを利用するプロジェクトでもGradleラッパーを同じ設定で利用していただくことを推奨します。
ProGuardを使用する場合は、以下のようにproguard-project.txt
を編集してください。
Validatorのクラス名を維持します。これは常に必須です。
-keep class com.androidformenhancer.validator.* { <init>(...); }
FormクラスとEntityクラスのメンバー(publicなフィールド)名を維持します。
FormHelper#create()
や@When
を使用する場合は必須です。
-keepclassmembers class com.androidformenhancer.sample.demos.DefaultForm {
public *;
}
-keepclassmembers class com.androidformenhancer.sample.demos.DefaultEntity {
public *;
}
JUnitテストコードはtestsフォルダに含まれています。 以下のコマンドでテストを実行できます。
./gradlew :androidformenhancer:connectedAndroidTest
手元にAndroid開発環境がなくても、Dockerがインストールされていれば、 以下のコマンドでDockerを使用してテストを実行することができます。
./test-docker.sh
注意: 現在、このスクリプトは動作しません。
このプロジェクトはTravis CIでmasterブランチへのPushをトリガーとしてビルドされています。
androidformenhancer/build/reports/androidTests/connected/index.html
ライブラリ本体部分(androidformenhancerフォルダ)のカバレッジをJaCoCoを使って計測しています。 Travis CIでのビルド結果はCoverallsで確認できます。
androidformenhancer/build/reports/coverage/debug/index.html
Copyright 2012 Soichiro Kashima
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.