techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

Data Bindingを使ってみる その3

前回前々回に引き続き、今回もData Bindingです。
今回は、"Import"について見ていきます。

<data>
    <import type="android.view.View"/>
</data>

Data Bindingを使用しているLayoutファイルの中では、クラスファイルをImportすることで、Layoutファイル内でJavaのようにImportしたクラスにアクセスすることができます。
例えば、以下のようなサンプルを見てみます。

[activity_main.xml]

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="android.view.View"/>         ・・・5行目
        <import type="monhaan.example.com.monhaan.Const"/>
        <variable name="activity" type="monhaan.example.com.monhaan.MainActivity"/>
        <variable name="hanter" type="monhaan.example.com.monhaan.Hanter"/>
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin">

            (・・・略・・・)

        <Spinner
            android:id="@+id/spn_weapon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/lbl_gender"></Spinner>

        <TextView
            android:id="@+id/lbl_selected_msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.format(Const.msg, hanter.weapon)}"  ・・・31行目
            android:visibility="@{hanter.isHaveWeapon? View.VISIBLE : View.INVISIBLE}"
            android:layout_below="@id/spn_weapon">

        </TextView>
    </RelativeLayout>
</layout>

[Const.java]

public class Const {
    public static String msg = "%sを装備しました。";
}

前回との違いは、武器を選択するためのSpinnerをLayoutファイルに追加しつつ、「<武器>が選択されました。」とメッセージを表示するためのTextViewを追加しています。
(ボタンは邪魔なので消しましたがあまり関係はありません。)

ポイントは、

1.5行目でandroid標準のViewパッケージをImportし、31行目でImportしたViewパッケージを利用し、TextViewのVisibleを設定しています。
31行目ではさらに、javaの三項演算子を用いて、後述するHanterクラスのhaveWeaponプロパティの値によって、Visible設定を切り替えています。
(武器を持っている場合はメッセージを表示、持っていない場合は非表示とする)

2.また、6行目で今回自分で新たに定義したConstクラスをImportし、32行目でImportしたConstクラスに定義したメッセージにアクセスしています。
さらに、"%s"の部分をString#formatメソッドを用いて武器名で置き換えています。
String#formatメソッドを使うにはjava.lang.*のImportが必要かと思いきや、どうやら自動でImportされるようです。

Activityは以下のように修正しています。

public class MainActivity extends AppCompatActivity {

    public Hanter hanter;
    public List<String> WEAPONS = Arrays.asList("装備なし","大剣","ハンマー");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActivityMainBinding binder = DataBindingUtil.setContentView(this, R.layout.activity_main);

            (・・・略・・・)

        // 武器を選択するためのSpinnetを準備
        ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
        adapter.addAll(WEAPONS);
        binder.spnWeapon.setAdapter(adapter);
        binder.spnWeapon.setOnItemSelectedListener(onItemSelectedListener);
    }

    public AdapterView.OnItemSelectedListener onItemSelectedListener = new AdapterView.OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if(position >= 1){
                // 武器を装備した
                hanter.setHaveWeapon(true);
                hanter.setWeapon(WEAPONS.get(position));   // 装備した武器の名前をHanterクラスのプロパティにセット
            }else{
                // 武器を装備していない
                hanter.setHaveWeapon(false);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    };
}

Hanterクラスには、前回と比較すると武器(weapon)と武器の所持状態を示すフラグ(haveWeapon)をそれぞれプロパティとして追加しています。

public class Hanter extends BaseObservable{
    private String name;
    private String gender;
    private boolean haveWeapon;
    private String weapon;

    public Hanter(String name, String gender){
        this.name = name;
        this.gender = gender;
        this.haveWeapon = false;
        this.weapon = "";
    }

            (・・・略・・・)

    @Bindable
    public String getWeapon() {
        return weapon;
    }

    public void setWeapon(String weapon) {
        this.weapon = weapon;
        notifyPropertyChanged(monhaan.example.com.monhaan.BR.weapon);
    }
}

実行結果は以下のような感じです。
f:id:uentseit:20160324225652p:plain:w200 f:id:uentseit:20160324225657p:plain:w200

上記の例では便宜上Constクラスにメッセージを定義していますが、strings.xmlを用いる場合は、以下のようにすることもできます。
[activity_main.xml]

            (・・・略・・・)
        <TextView
            android:id="@+id/lbl_selected_msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{@string/msg_have_weapon(hanter.weapon)}"    ・・・6行目
            android:visibility="@{hanter.isHaveWeapon? View.VISIBLE : View.INVISIBLE}"
            android:layout_below="@id/spn_weapon">
        </TextView>
            (・・・略・・・)

6行目でstrings.xmlからメッセージ文字列を取得しつつ、%sに武器をバインドしています。

[strings.xml]

<resources>
    <string name="app_name">MonHaan</string>
    <string name="msg_have_weapon">%sを装備しました。</string>
</resources>

さて、今日はここまでにします。