Posted at

ListFragmentを使ってみる[Android]

More than 5 years have passed since last update.


はじめに

 ListFragmentの使い方を勉強。

 基礎の基礎は少し調べればすぐ出るけど、表示するデータは自分で作成したクラスのデータにしたい、ということで検索検索。

 自分なりにまとめてみますことに。


環境

OS X 10.9.3

Android Studio (Beta) 0.8.0

Sony SOL25 Android 4.4.2(API 19)


ListFragment

 Fragmentを用いて簡単に(?)Listを表示させることができるモノです、誤解を恐れながら言うと。

 Fragmentを用いたActionBarによるTab表示で作成したProjectを参考にしながら、ちょこちょこ変えていきました。

 今回は、タブを2つにし、ひとつをListFragmentとしてTabにSetしました。

 前置きが長い、ザクっと行きます。


Itemクラス

 サンプルに作った適当なデータクラスです。idと名前を持った簡単なモノですね。


Item.java

public class Item implements Parcelable{

public String id;
public String name;

public Item(String id, String name) {
this.id = id;
this.name = name;
}

public Item(Parcel in){
this.id = in.readString();
this.name = in.readString();
}

@Override
public void writeToParcel(Parcel dest, int flags){
dest.writeString(id);
dest.writeString(name);
}

@Override
public int describeContents() {
return 0;
}//FileDescriptor未使用の場合は0

// 今は定型文という認識で
public static final Creator<Item> CREATOR = new Creator<Item>() {
public Item createFromParcel(Parcel in) {
return new Item(in);
}

public Item[] newArray(int size) {
return new Item[size];
}
};
}



Parcelableクラス

 独自にデータクラスを作成した場合に都合がいい模様(適当でごめんなさい)。必要があれば調べてまとめたいところ。

 注意点としては、writeToParcel(Parcel dest, int flags)で書き込む順番とItem(Parcel in)で読み出す順番を同じにするところだそうです。気をつけよう。

今回に関してはあまり関係ないです。


ListFragmentをextendsしたクラス作成

 データを表示するフラグメントですね。今回はListViewだけでは悲しいので、ボタンを3つ設けちゃいました。


ItemListFragment.java

//import等は割愛

public class ItemListFragment extends ListFragment {

private ItemListAdapter adapter;

public ItemListFragment() {
}

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

//set adapter
adapter = new ItemListAdapter(getActivity());
setListAdapter(adapter);
}

@Override
public void onStart() {
super.onStart();

this.getView().findViewById(R.id.one).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
adapter.add("1", "button1");
}
});
this.getView().findViewById(R.id.two).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
adapter.add("2", "button2");
}
});
this.getView().findViewById(R.id.three).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
adapter.add("3", "button3");
}
});

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.item_listfragment, container, false);
}

}


 ボタンを押すとItemがListViewに追加されるという寸法です。レイアウトも見ていきます。


item_listfragment.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<Button
android:id="@+id/one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="1"/>
<Button
android:id="@+id/two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="2"/>
<Button
android:id="@+id/three"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="3"/>

</LinearLayout>

<ListView
android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"/>

//データがない場合に表示される
<TextView
android:id="@id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="No data"
android:textSize="32sp"/>

</LinearLayout>



ListAdapter

 AdapterはListViewとデータをつなげる重要人物です。

 こちらを参考にさせていただきました。非常に説明が細かくされており、勉強になります。もう、私のよりここをみたほうがよいかも。悲しい。


ItemListAdapter.java

public class ItemListAdapter extends ArrayAdapter<Item> {

// 見易さのために定義。普段は直接 getView で指定する。
private static final int resource = R.layout.custom_listview_item;

public ItemListAdapter(Context context){
super(context, 0);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// super.getView() は 呼ばない(カスタムビューにしているため)
View view;

// テンプレート処理。
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
}

// データをgetItemで取る
Item item = getItem(position);

// カスタムビューの場合はViewが確実にあるtry-catch は不要ためか。
TextView id = (TextView) view.findViewById(R.id.id);
id.setText(item.id);
TextView name = (TextView) view.findViewById(R.id.name);
name.setText(item.name);

return view;
}

// 設定されている CustomListItem の ArrayList を返す。
// 縦横切替などでデータを移行するために使う。
public ArrayList<Item> getItemList() {
// 今回は Bundle#putParcelableArrayList() を使うことを想定する。
// 必要に応じて Bundle#putSparseParcelableArray() を使ってもいい。

int size = getCount();
ArrayList<Item> itemList = new ArrayList<Item>(size);
for (int index = 0; index < size; index++) {
itemList.add(getItem(index));
}
return itemList;
}

// Bundleから復元するときに必要になるはず。
public void addAll(ArrayList<Item> parcelableArrayList) {
// 強制でキャスト。落ちる場合は、設計か実装が間違っている。
@SuppressWarnings("unchecked")
ArrayList<Item> itemList = (ArrayList<Item>) parcelableArrayList;
super.addAll(itemList);
}

public void add(String id, String name) {
Item item = new Item(id, name);
super.add(item);
}

// 削除
public void remove(int index) {
if (index < 0 || index >= getCount()) {
return;
}
remove(getItem(index));
}
}



その他のクラス

 あとはもうひとつのタブに適当なフラグメントをSetします。それだけ。

 カスタムビューを一応作りました、適当ですね。


custom_listview_item.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_margin="8dp"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/id"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_weight="1"
android:background="@drawable/border"
android:gravity="center"
android:text="id"/>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:paddingLeft="16dp"
android:layout_weight="4"
android:background="@drawable/border"
android:gravity="center_vertical"
android:text="name"/>

</LinearLayout>



実行確認

私の実機(Sony SOL25)で動作を確認しました。

Screenshot_2014-07-14-03-43-35.png


おわりに

GithubにてProjectを公開しております。割愛した説明はここを見てもらえれば。

また、説明不足が際立つ(説明してない)。メモとして見返してこれでわかるか、いや、わかるまい。質問等あれば適宜、追記したいところ。なくても追記したいところ。

ご指摘やアドバイス等を頂けると本当に幸いです。


参考

技術見聞録 - ListViewのカスタムビューを作るときにやるべきこと

Android Parcelable を使ってクラスのメンバを一時保存

美しいOnClickListenerの実装方法(を教えてください)

ListFragment | Android Developers