こんにちは、まっさん(@Tera_Msaki)です。
この記事は Android スマホ用のアプリ開発の中で、
今後の開発で再使用性が高いと思われるコーディングをまとめたものです。
Java での開発経験、XML 構文規則、Android のアプリ開発経験がある方を対象としています。
Android のアプリ開発でお役にたててれば、嬉しいです。
(これから Android のアプリ開発や Java での開発を始めたい方への案内は、記事の最後で紹介します)
表示できる行数を指定できるListViewを実装する
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つのパーセルを引き渡す実装としています。
インタフェースを使用して、アクティビティ(またはフラグメント)側で、
選択した内容に応じた処理を記述します。

10件以上ある場合は、スクロールします。
スクロール途中で止めているため、表示が切れているようにみえます。

◎ダイアログのレイアウト
<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)などを
指定してください。
今回は、ここまでです。
誤字脱字、意味不明でわかりづらい、
もっと詳しく知りたいなどのご意見は、
このページの最後にあるコメントか、
こちらから、お願いいたします♪
ポチッとして頂けると、
次のコンテンツを作成する励みになります♪

これからAndroidのアプリ開発やJavaでの開発を始めたい方へ
初めての Android のアプリ開発では、アプリケーション開発経験がない方や、
アプリケーション開発経験がある方でも、Java や C# などのオブジェクト指向言語が初めての方は、
書籍などによる独学ではアプリ開発できるようになるには、
かなりの時間がかかりますので、オンラインスクールでの習得をおススメします。
未経験者からシステムエンジニアを目指すのに最適かと、
まずは無料相談から♪

無料でJava言語を学べるのは、かなり魅力的♪
でも、応募資格は35歳以下です、、、
2022年12月から説明会が土曜日開催が追加されていますよ♪
説明会では、希望者に対してプログラミング体験もできるよ♪

未経験者からプログラマーを目指すのに最適かと、
まずは無料カウンセリングから♪

カリキュラムとサポートがしっかりしています、
お得なキャンペーンとかいろいろやっています♪

ゲーム系に強いスクール、UnityやUnrealEngineを習得するのに最適かと、
まずは無料オンライン相談から♪

参考になったら、💛をポッチとしてね♪
コメント欄