こんにちは、まっさん(@Tera_Msaki)です。
この記事は Android スマホ用のアプリ開発の中で、
今後の開発で再使用性が高いと思われるコーディングをまとめたものです。
Java での開発経験、XML 構文規則、Android のアプリ開発経験がある方を対象としています。
Android のアプリ開発でお役にたててれば、嬉しいです。
(これから Android のアプリ開発や Java での開発を始めたい方への案内は、記事の最後で紹介します)
ListView は、Andoroid アプリでリスト表示するベーシックライブラリです。
選択肢をリスト表示し、利用者に選択させる場合に使用します。
ListView は、使い勝手が良いライブラリですが、選択肢があらかじめ決まっているような場合は、標準的な使用方法(ListViewの高さを指定)で問題ありません。
しかし、選択肢の数が決まっていない場合、ListView の表示できる行数を指定することができないため、件数が多いと表示領域が画面全体に及んだり、逆に少ない場合は、表示領域を余らすことになります。
今回、表示できる行数を指定できる ListView の実装について、説明したいと思います。
ListViewを使用したダイアログ画面
利用者に選択肢を選択させる場合、選択肢をリスト表示するダイアログ画面がよく使用されます。
リスト表示する選択肢の数が可変で、表示できる行数を指定できる ListView をもつ、ダイアログ画面を実装します。
public class CustomDialogList extends DialogFragment {
private static final boolean DEBUG = false;
private static final String TAG = CustomDialogList.class.getSimpleName();
private CustomDialogItemListener customDialogItemListener = null;
private final int[] layout = {0,R.layout.dialog_list};
private final int[] listLayout = {0, R.layout.item_dialog};
private final int[] item = {0, R.id.item};
private final int[] id = {0,R.id.dialog_item};
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
String title = requireArguments().getString("TITLE");
int max = requireArguments().getString("MAX") != null ? Integer.parseInt(requireArguments().getString("MAX")) : 10;
CustomDialogParcel[] customDialogParcels = (CustomDialogParcel[]) requireArguments().getParcelableArray("PAC");
Dialog dialog = new Dialog(getActivity());
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
dialog.setContentView(layout[customDialogParcels.length]);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int dialogWidth = (int) (displayMetrics.widthPixels * 0.98f);
int dialogHeight = (int) (displayMetrics.heightPixels * 0.98f);
WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();
layoutParams.width = (Math.min(dialogWidth, dialogHeight));
dialog.getWindow().setAttributes(layoutParams);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.setCanceledOnTouchOutside(true);
// タイトル
TextView textView = dialog.findViewById(R.id.dialog_title);
textView.setText(title);
// リスト
ListView listView = dialog.findViewById(id[customDialogParcels.length]);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getActivity(), listLayout[customDialogParcels.length], item[customDialogParcels.length]);
for (String string : customDialogParcels[0].getValue().split("\t"))
arrayAdapter.add(string);
listView.setAdapter(arrayAdapter);
listView.setOnItemClickListener((parent, view, position, id) -> {
if (customDialogItemListener != null)
customDialogItemListener.doItemClick(parent, view, position, id);
dismiss();
});
dialog.findViewById(R.id.dialog_close).setOnClickListener(view -> {
if (customDialogItemListener != null)
customDialogItemListener.doCloseClick(view);
dismiss();
});
setListViewHeight(listView, max);
return dialog;
}
private void setListViewHeight(ListView listView, int max) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) { return; }
int height = 0;
int count = Math.min(listAdapter.getCount(), max);
for (int i = 0 ; i < count ; i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
height += listItem.getMeasuredHeight();
}
float dp = getResources().getDisplayMetrics().density;
ViewGroup.LayoutParams params = listView.getLayoutParams();
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) params;
params.height = height + (int)(marginLayoutParams.topMargin / dp) + (int)(marginLayoutParams.bottomMargin / dp)
+ (int)(listView.getPaddingTop() / dp) + (int)(listView.getPaddingBottom() / dp);
listView.setLayoutParams(params);
}
public void setCustomDialogItemListener(CustomDialogItemListener customDialogItemListener) {
this.customDialogItemListener = customDialogItemListener;
}
@Override
public void onDetach() {
super.onDetach();
if (customDialogItemListener != null)
customDialogItemListener = null;
}
}
ダイアログ画面の呼び出す際の引数で、ダイアログのタイトル( TITLE )、表示できる行数( MAX )を指定しています。リスト表示する選択肢は、タブ区切りでバックし、パーセル( customDialogParcels )を使用して、引き渡しています。ListView の高さは、ListView にセットするアダプタから、リスト数が表示できる行数以下はリスト数、以上は表示できる行数として、ListView に表示するアイテムの高さ、上下マージンとパディングを考慮して、ListView の高さを再計算して、設定しています。
パーセル( customDialogParcels )
アクティビティ(またはフラグメント)からダイアログを呼び出す際、値や属性などを構造化したパーセルにして引き渡す実装がスマートです。
構造化する部分は、用途に応じてカスタムします。
public class CustomDialogParcel implements Parcelable {
private String property;
private int type;
private int length;
private String value;
// コンストラクタ //
public CustomDialogParcel() { }
public CustomDialogParcel(String property, int type, int length, String value) {
this.property = property;
this.type = type;
this.length = length;
this.value = value;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(property);
dest.writeInt(type);
dest.writeInt(length);
dest.writeString(value);
}
@Override
public int describeContents() {
return 0;
}
protected CustomDialogParcel(Parcel in) {
property = in.readString();
type = in.readInt();
length = in.readInt();
value = in.readString();
}
public static final Creator<CustomDialogParcel> CREATOR = new Creator<CustomDialogParcel>() {
@Override
public CustomDialogParcel createFromParcel(Parcel in) {
return new CustomDialogParcel(in);
}
@Override
public CustomDialogParcel[] newArray(int size) {
return new CustomDialogParcel[size];
}
};
public String getProperty() {
return property;
}
public String getValue() {
return value;
}
public int getType() {
return type;
}
public int getLength() {
return length;
}
public void setType(int type) {
this.type = type;
}
public void setLength(int length) {
this.length = length;
}
public void setValue(String value) {
this.value = value;
}
}
構造化する内容は、入力ダイアログでの用途を想定して、プロパティ名( String )、型( int )、長さ( int )、値( String )としています。
ダイアログの呼び出し
ダイアログのタイトル( TITLE )、表示できる行数( MAX )、リスト表示する選択肢は、タブ区切りでバックしたパーセル( customDialogParcels )を設定してダイアログを呼び出します。
:
String itemLists = itemList[0];
for (int i = 1; i < itemList.length; i++) {
itemLists = String.format("%s\t%s", itemLists, itemList[i]);
}
Bundle bundle = new Bundle();
bundle.putString("TITLE", title);
bundle.putString("MAX", "10");
customDialogParcels = new CustomDialogParcel[1];
customDialogParcels[0] = new CustomDialogParcel("non", 0, 0, itemLists);
bundle.putParcelableArray("PAC", customDialogParcels);
CustomDialogList customDialogList = new CustomDialogList();
customDialogList.setCustomDialogItemListener(new CustomDialogItemListener() {
@Override
public void doItemClick(AdapterView<?> parent, View view, int position, long id) {
// 選択した内容に応じた処理を記述する
:
}
@Override
public void doCloseClick(View view) {
// 処理があれば、ここに記述する
:
}
});
fragmentManager = getSupportFragmentManager();
customDialogList.setArguments(bundle);
customDialogList.show(fragmentManager, title);
:
選択肢の数だけパーセルを用意する実装も可能ですが、タブ区切りでバックした1つのパーセルを引き渡す実装としています。インタフェースを使用して、アクティビティ(またはフラグメント)側で選択した内容に応じた処理を記述します。
◎ダイアログのレイアウト
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
:
android:layout_alignParentTop="true"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:paddingBottom="8dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
:
android:gravity="center"
android:padding="4dp"/>
<ListView
android:id="@+id/dialog_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:paddingBottom="16dp" />
</LinearLayout>
<Button
android:id="@+id/dialog_close"
android:layout_width="30dp"
android:layout_height="30dp"
:
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"/>
</RelativeLayout>
使用する環境に応じた背景( background )や文字サイズ( testSize )、色( textColor )などを指定してください。
◎ListViewに表示するアイテムのレイアウト
LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:layout_editor_absoluteX="8dp">
<TextView
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
:
android:padding="3dp"/>
</LinearLayout>
使用する環境に応じた背景( background )や文字サイズ( testSize )、色( textColor )などを指定してください。
今回は、ここまでです。
誤字脱字、意味不明でわかりづらい、
もっと詳しく知りたいなどのご意見は、
このページの最後にあるコメントか、
こちらから、お願いいたします♪