複雑な形状のViewの一覧を作成する
ListViewを使えば複雑な形状のViewの一覧を作成できる。
参考:
SimpleAdapterのsample code
しかし、この技法の欠点は、書き込み可能なView、例えば、EditTextを配置しても、そのEditTextに対して利用者が書き込みを行うことはできない、ということである。
ListViewのような作り込まれたものは、プログラミングが終わった後で、予期しない不都合が判明する。
素直に、ScrollView & LayoutInflaterを使って、地道に作成する。
ただし、この場合、
EditTextにはIDを与えてはいけない、という点に留意しなければならない。
例えば、次のxmlのように、android:id="@+id/EditText"を設けてはいけない。削除しよう。
<EditText
android:id="@+id/EditText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</EditText>
仮に、IDを設けたとしても、初回起動時には、上手く表示される。しかし、configuration changeに伴う再起動が発生した後で表示されるEditTextには、全て同一の文字列が代入されてしまう。
この問題を避けるために、ID指定を書いてはいけないのである。
TextViewの場合はID指定をしても問題は発生しない。
main.xmlは次のとおりである。IDがParentListのLinearLayoutに、複数の子Viewを動的に追加する。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:id="@+id/ParentList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
</LinearLayout>
</ScrollView>>
</LinearLayout>
上記のxmlの中に、次のlistitem.xmlを動的に挿入する。各ViewにはIDを付けていない。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:background="#555"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#000"
>
<CheckBox
android:text="@string/Apply"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</CheckBox>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:text="@string/Before"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
</TextView>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:text="@string/After"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
</TextView>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</EditText>
</LinearLayout>
</LinearLayout>
</LinearLayout>
上記2個のxmlを使って、複数のViewを動的に生成し、一覧を作成するJavaのcodeは次のとおりである。ViewのIDが存在しないため、個々のViewの識別はアドレス(相対位置と表現して良いかもしれない)で行う。
public class InflateListActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
setContentView(R.layout.main);
int i;
ArrayList<String> al;
BackupData bd;
bd = (BackupData)getLastNonConfigurationInstance();
if(bd==null){
//サンプルプログラムなので適当にデータを代入する。
al = new ArrayList<String>();
al.add("true");
al.add("Green");
al.add("Blue");
al.add("false");
al.add("Green");
al.add("Blue");
al.add("true");
al.add("Green");
al.add("Blue");
al.add("false");
al.add("Red");
al.add("Blue");
al.add("true");
al.add("Yellow");
al.add("Red");
}
else{//configuration changeに伴う再起動
al = bd.getBackupData();
}
for(i=0; i<al.size()/3; i++){
LayoutInflater inf;
LinearLayout llParent, ll, ll2, llChild;
CheckBox cb;
EditText et;
String s;
//親Viewを取得する。
llParent = (LinearLayout)findViewById(R.id.ParentList);
//挿入する子Viewを作成する。
inf = getLayoutInflater();
ll = (LinearLayout)inf.inflate(R.layout.listitem, null);
ll2 = (LinearLayout)ll.getChildAt(0);
//子Viewにデータを入れる。
cb = (CheckBox)ll2.getChildAt(0);
s = al.get(i*3);
if(s.equals("true")==true) cb.setChecked(true);
else cb.setChecked(false);
llChild = (LinearLayout)ll2.getChildAt(1);
et = (EditText)llChild.getChildAt(1);
et.setText(al.get(i*3+1));
llChild = (LinearLayout)ll2.getChildAt(2);
et = (EditText)llChild.getChildAt(1);
et.setText(al.get(i*3+2));
//親Viewに子Viewを入れる。
llParent.addView(ll);
}
}
//configuration changeに伴う再起動への対応
@Override
public Object onRetainNonConfigurationInstance(){
ArrayList<String> al;
BackupData bd;
LinearLayout llParent;
int i, iSize;
al = new ArrayList<String>();
llParent = (LinearLayout)findViewById(R.id.ParentList);
iSize = llParent.getChildCount();
for(i=0; i<iSize; i++){
LinearLayout ll, ll2, llChild;
CheckBox cb;
EditText et;
String s;
ll = (LinearLayout)llParent.getChildAt(i);
ll2 = (LinearLayout)ll.getChildAt(0);
cb = (CheckBox)ll2.getChildAt(0);
if(cb.isChecked()==true) s = "true";
else s = "false";
al.add(s);
llChild = (LinearLayout)ll2.getChildAt(1);
et = (EditText)llChild.getChildAt(1);
s = et.getText().toString();
al.add(s);
llChild = (LinearLayout)ll2.getChildAt(2);
et = (EditText)llChild.getChildAt(1);
s = et.getText().toString();
al.add(s);
}
bd = new BackupData();
bd.setBackupData(al);
return bd;
}
private class BackupData{
private ArrayList<String> dataBackup;
void setBackupData(ArrayList<String> al){
dataBackup = al;
}
ArrayList<String> getBackupData(){
return dataBackup;
}
}
}