この記事は Androidスマホ用のアプリ開発の中で、
今後の開発で再使用性が高いと思われるコーディングをまとめたものです。
Java での開発経験、XML構文規則、Android のアプリ開発経験がある方を対象としています。
Android のアプリ開発でお役にたててれば、嬉しいです。
(これから Android のアプリ開発や Java での開発を始めたい方への案内は、記事の最後で紹介します)
ポイント
Andoridアプリの開発で、選択肢をリスト表示する場合に、ListViewを使用することが多いと思います。
リストの一覧から選択後に ListView を再表示させた場合、スクロール位置がリセットされます。
開発者からすると当たり前の動作ですが、選択の度にスクロール位置がリセットされると、操作性が著しく低下します。スクロール位置を保持して状態で、ListViewを再表示する仕組みを実装します。
RecyclerViewでスクロール位置を保持する方法はこちらです↓↓↓
ListView
ListView を使うシーンとして、子画面(ダイアログ)を使用する場合が多いかと思います。
DialogFragment を継承したリスト選択ダイアログをサンプルに、スクロール位置を保持した状態で、ListView を再表示する方法について、説明します。
スクロール位置を取得する
リスト選択ダイアログを呼び出す側とのインタフェースとして、CustomDialogItemListener を用意します。
再表示の際に使用するスクロール位置の初期値は、コンストラクタで引き渡します。
選択時のスクロール位置は、getFirstVisiblePosition() で取得して、CustomDialogItemListener のアイテム選択をイベント通知します。
リスト選択ダイアログを呼び出す側からは、インスタンス化したリスト選択ダイアログのスクロール位置を直接参照するか、スクロール位置を参照する Getter を用意します。
public class CustomDialogList extends DialogFragment {
private CustomDialogItemListener customDialogItemListener = null;
private final Context context;
public int current;
:
public CustomDialogList(Context context, int current) {
this.context = context;
this.current = current;
}
:
listView.setOnItemClickListener((parent, view, position, id) -> {
if (customDialogItemListener != null) {
current = listView.getFirstVisiblePosition();
customDialogItemListener.doItemClick(parent, view, position, id);
}
dismiss();
});
:
public void setCustomDialogItemListener(CustomDialogItemListener customDialogItemListener) {
this.customDialogItemListener = customDialogItemListener;
}
@Override
public void onDetach() {
super.onDetach();
if (customDialogItemListener != null) customDialogItemListener = null;
}
リスト選択ダイアログのインタフェース(CustomDialogItemListener)
アイテム選択と閉じる操作をイベント通知するためのインタフェース
public interface CustomDialogItemListener extends EventListener {
void doItemClick(AdapterView<?> parent, View view, int position, long id);
void doCloseClick(View view);
}
スクロール位置を保持した状態で、ListViewを表示する
保持したスクロール位置を先頭に ListView する場合は、setSelection あるいは、setSelectionFromTop を使用します。
setSelectionFromTop では、先頭行のスクロール位置をピクセル単位で指定できます。
getChildAt() で ListView のアイテムを取得し、getTop() で ListView からの相対位置を取得します。
サンプルでは、リスト選択ダイアログの最大行表示( setListViewHeight )と、選択行のテキスト色を変更(後述)しています。
:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
:
setListViewHeight(listView, max);
int i = listView.getChildAt(0) != null ? listView.getChildAt(0).getTop() : 0;
listView.setSelectionFromTop(current, i);
return dialog;
}
ListView の最大行表示(setListViewHeight)
指定した行数で ListView の高さを調整します。
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);
}
表示できる行数を指定できるListView について、詳しくは↓↓↓
選択行のテキスト色を変える
ListView の表示は ArrayAdapter を使用します。
選択行のテキスト色を変更するには、getView をオーバライドして、表示行が選択行の場合に、テキスト色を変更したり、テキストのスタイルを変更します。
:
ListView listView = dialog.findViewById(R.id.dialog_item);
ArrayList<String> arrayList = new ArrayList<>();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(), R.layout.item_dialog, R.id.item) {
@SuppressLint("UseCompatLoadingForDrawables")
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
if (convertView == null) convertView = LayoutInflater.from(context).inflate(R.layout.item_dialog, parent, false);
TextView textView = convertView.findViewById(R.id.item);
textView.setTextColor(position == pos ? context.getColor(R.color.red) : context.getColor(R.color.black));
textView.setTypeface(position == pos ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
textView.setText(arrayList.get(position));
return convertView;
}
};
:
listView.setAdapter(arrayAdapter);
:
リスト選択ダイアログの呼び出し
リスト表示するテキストは、タブ区切りでバックし、パーセル( customDialogParcels )を使用して、引き渡します。
Activity 間の遷移がある場合は、Bundle を使用して、スクロール位置を保持します。
Bundle の保持は、SaveCondition と RestoreCondition を使用します。
:
private int current;
:
private Bundle SaveCondition(Bundle bundle) {
bundle.putString("current", String.valueOf(current));
:
}
:
private void RestoreCondition(Bundle bundle) {
current = Integer.parseInt(bundle.getString("current"));
:
}
:
// リストダイアログ
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");
bundle.putString("POS", String.valueOf(pos));
customDialogParcels = new CustomDialogParcel[1];
customDialogParcels[0] = new CustomDialogParcel("non", 0, 0, itemLists);
bundle.putParcelableArray("PAC", customDialogParcels);
CustomDialogList customDialogList = new CustomDialogList(context, current);
customDialogList.setCustomDialogItemListener(new CustomDialogItemListener() {
@Override
public void doItemClick(AdapterView<?> parent, View view, int position, long id) {
Bundle bundle;
bundle = customDialogList.getArguments();
customDialogParcels = (CustomDialogParcel[]) Objects.requireNonNull(bundle).getParcelableArray("PAC");
current = customDialogList.current;
:
}
}
public void doCloseClick(View view) {
// 処理があれば、ここに記述する
}
});
fragmentManager = getSupportFragmentManager();
customDialogList.setArguments(bundle);
customDialogList.show(fragmentManager, title);
:
パーセル( 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;
}
}
今回は、ここまでです。
ListViewでスクロール位置を保持する方法 を使用している Androidアプリです。
誤字脱字、意味不明でわかりづらい、
もっと詳しく知りたいなどのご意見は、
このページの最後にあるコメントか、
こちらから、お願いいたします♪
ポチッとして頂けると、
次のコンテンツを作成する励みになります♪
これからAndroidのアプリ開発やJavaでの開発を始めたい方へ
初めての Android のアプリ開発では、アプリケーション開発経験がない方や、
アプリケーション開発経験がある方でも、Java や C# などのオブジェクト指向言語が初めての方は、
書籍などによる独学ではアプリ開発できるようになるには、
かなりの時間がかかりますので、オンラインスクールでの習得をおススメします。
未経験者からシステムエンジニアを目指すのに最適かと、
まずは無料相談から♪
未経験者からプログラマーを目指すのに最適かと、
まずは無料カウンセリングから♪
カリキュラムとサポートがしっかりしています、
お得なキャンペーンとかいろいろやっています♪
ゲーム系に強いスクール、UnityやUnrealEngineを習得するのに最適かと、
まずは無料オンライン相談から♪
参考になったら、💛をポッチとしてね♪
コメント欄