getChildAt(i)
on は a の直接の子のみを取得しViewGroup
ます。ネストされたループを実行せずにすべての子にアクセスすることは可能ですか?
8 に答える
この回答を書いている時点で、受け入れられた回答には、結果に重複が含まれるという欠陥があります。
再帰に頭を悩ませている人のために、非再帰的な代替手段があります。これが、他の回答の深さ優先アプローチに代わる幅優先検索でもあることに気付くと、ボーナスポイントが得られます。
private List<View> getAllChildrenBFS(View v) {
List<View> visited = new ArrayList<View>();
List<View> unvisited = new ArrayList<View>();
unvisited.add(v);
while (!unvisited.isEmpty()) {
View child = unvisited.remove(0);
visited.add(child);
if (!(child instanceof ViewGroup)) continue;
ViewGroup group = (ViewGroup) child;
final int childCount = group.getChildCount();
for (int i=0; i<childCount; i++) unvisited.add(group.getChildAt(i));
}
return visited;
}
いくつかの簡単なテスト (正式なものはありません) は、この代替手段も高速であることを示唆していArrayList
ますが、これは、他の回答が作成する新しいインスタンスの数に関係している可能性が最も高いです。また、結果は、ビュー階層の垂直方向/水平方向によって異なる場合があります。
(ソース)
すべての子ビューと children 内のビューを取得する場合はViewGroups
、再帰的に取得する必要があります。これは、API に既定でこれを行うための規定がないためです。
private ArrayList<View> getAllChildren(View v) {
if (!(v instanceof ViewGroup)) {
ArrayList<View> viewArrayList = new ArrayList<View>();
viewArrayList.add(v);
return viewArrayList;
}
ArrayList<View> result = new ArrayList<View>();
ViewGroup viewGroup = (ViewGroup) v;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
ArrayList<View> viewArrayList = new ArrayList<View>();
viewArrayList.add(v);
viewArrayList.addAll(getAllChildren(child));
result.addAll(viewArrayList);
}
return result;
}
これにより、階層内のすべてのビューを含む ArrayList が得られ、それを繰り返し処理できます。
基本的に、このコードは、階層内に別の ViewGroup が見つかった場合にそれ自体を呼び出し、より大きな ArrayList に追加される ArrayList を返します。
このメソッドを再帰的に再実装しました。MH よりも速いかどうかはわかりませんが、少なくとも重複はありません。
private List<View> getAllViews(View v) {
if (!(v instanceof ViewGroup) || ((ViewGroup) v).getChildCount() == 0) // It's a leaf
{ List<View> r = new ArrayList<View>(); r.add(v); return r; }
else {
List<View> list = new ArrayList<View>(); list.add(v); // If it's an internal node add itself
int children = ((ViewGroup) v).getChildCount();
for (int i=0;i<children;++i) {
list.addAll(getAllViews(((ViewGroup) v).getChildAt(i)));
}
return list;
}
}
MHの回答には、メソッドに与えられている親ビューが含まれているため、この補助メソッド(呼び出されるメソッド)を作成しました。
つまり、TextView (子を持たない) でこのメソッドを呼び出すと、1 ではなく 0 が返されます。
private List<View> getAllChildren(View v) {
List list = getAllViews(v);
list.remove(v);
return list;
}
TLDR: すべての子をカウントするには、両方のメソッドをコピーして貼り付け、getAllChildren() を呼び出します
それが良いかどうかはわかりません.onViewAdded(View child)メソッドをオーバーライドして、ビューを追加するだけです.ドキュメンテーションで.これは、カスタムビューグループを作成するときにList<View>
役立ちます.
この ViewGroup に新しい子が追加されると呼び出されます。オーバーライドは常に super.onViewAdded を呼び出す必要があります。
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
views.add(child);//add in list and then use it later
}
これは、階層を次のように出力する私の(再帰的な)ソリューションです。
android.widget.LinearLayout children:2 id:-1
android.view.View id:2131624246
android.widget.RelativeLayout children:2 id:2131624247
android.support.v7.widget.AppCompatTextView id:2131624248
android.support.v7.widget.SwitchCompat id:2131624249
public static String getViewHierarcy(ViewGroup v) {
StringBuffer buf = new StringBuffer();
printViews(v, buf, 0);
return buf.toString();
}
private static String printViews(ViewGroup v, StringBuffer buf, int level) {
final int childCount = v.getChildCount();
v.getId();
indent(buf, level);
buf.append(v.getClass().getName());
buf.append(" children:");
buf.append(childCount);
buf.append(" id:"+v.getId());
buf.append("\n");
for (int i = 0; i < childCount; i++) {
View child = v.getChildAt(i);
if ((child instanceof ViewGroup)) {
printViews((ViewGroup) child, buf, level+1);
} else {
indent(buf, level+1);
buf.append(child.getClass().getName());
buf.append(" id:"+child.getId());
buf.append("\n");
}
}
return buf.toString();
}
private static void indent(StringBuffer buf, int level) {
for (int i = 0; i < level; i++) {
buf.append(" ");
}
}