Android-ビュー内に子供を入れますか?


169

ビューを指定すると、その中に子ビューを取得するにはどうすればよいですか?

だから私はカスタムビューを持っていて、デバッガーはmChildren他に7つのビューがあることを示しています これらのビューにアクセスする方法が必要ですが、これを行うためのパブリックAPIはないようです。

助言がありますか?

編集:

私のカスタムビューは AdapterView

回答:


313
for(int index = 0; index < ((ViewGroup) viewGroup).getChildCount(); index++) {
    View nextChild = ((ViewGroup) viewGroup).getChildAt(index);
}

それでいいですか?


2
これを再帰的に実行して、ビュー階層JSONオブジェクトを生成する最良の方法は何ですか?
ジンボブ2016年

親ビューに名前が付けられていると仮定しますviewGroup
Prime624

57

すべての直接の子だけでなくすべての子の子などを取得する場合は、再帰的に行う必要があります。

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 vg = (ViewGroup) v;
    for (int i = 0; i < vg.getChildCount(); i++) {

        View child = vg.getChildAt(i);

        ArrayList<View> viewArrayList = new ArrayList<View>();
        viewArrayList.add(v);
        viewArrayList.addAll(getAllChildren(child));

        result.addAll(viewArrayList);
    }
    return result;
}

結果を使用するには、次のようにします。

    // check if a child is set to a specific String
    View myTopView;
    String toSearchFor = "Search me";
    boolean found = false;
    ArrayList<View> allViewsWithinMyTopView = getAllChildren(myTopView);
    for (View child : allViewsWithinMyTopView) {
        if (child instanceof TextView) {
            TextView childTextView = (TextView) child;
            if (TextUtils.equals(childTextView.getText().toString(), toSearchFor)) {
                found = true;
            }
        }
    }
    if (!found) {
        fail("Text '" + toSearchFor + "' not found within TopView");
    }

8
たとえば、子はViewタイプではなくViewタイプである可能性があるため、この呼び出しは保存されません。そのため、キャストが失敗すると、getAllChildrenの再帰呼び出しで例外が発生する可能性があります。したがって、if(!(v instanceof ViewGroup))returnを追加する必要があります。キャスト前
Phil

2
小さな提案:forループをfor (int i = 0, n = vg.getChildCount(); i < n; i++) Androidで置き換えると、メソッドを呼び出す代わりにローカル変数にアクセスする方がはるかに高速になる傾向があります。このように、メソッドはビューグループごとに1回だけ呼び出され、その後の実行ではローカル変数が使用されます。
ArtOfWarfare 2012年

Phil Diegmannの提案により、コードを変更しました。お役に立てれば。私のために働く。
IHeartAndroid 2013年

1
涼しい。私は、ブール値の「includeViewGroups」を追加することのみをお勧めします。これは、アダプターでの反復処理に役立ちます(また、リーフだけが必要です)。ありがとう!
JRun

20

View.findViewById()http://developer.android.com/reference/android/view/View.html#findViewById (int)を使用して、いつでも子ビューにアクセスできます。

たとえば、アクティビティ/ビュー内:

...
private void init() {
  View child1 = findViewById(R.id.child1);
}
...

または、ビューへの参照がある場合:

...
private void init(View root) {
  View child2 = root.findViewById(R.id.child2);
}

私はIDにアクセスできません。UIはコードを介して生成されます。私はrobotiumを使用してオートメーションを作成しているため、実行できることが制限されています
aryaxt

@jonson、すべての子を取得する必要がある場合はまったく役に立ちません。
Pacerier

また、quora.com
unanswered

17

この回答Viewは、ビュー階層内のすべての子を検出するための@IHeartAndroidの再帰アルゴリズムの代替として提供します。この記事の執筆時点では、再帰的なソリューションには欠陥があり、結果に重複が含まれることに注意してください。

再帰に頭を悩ませるのに苦労している人のために、非再帰的な代替案があります。これが再帰的ソリューションの深さ優先アプローチの幅優先検索の代替手段であることを理解すると、ボーナスポイントを獲得できます。

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ますが、他の回答が作成する新しいインスタンスの数に関係している可能性が最も高くなります。また、ビュー階層の垂直/水平方向によって結果が異なる場合があります。

クロス投稿:Android | ViewGroupのすべての子要素を取得します。


7

ここに提案があります:与えられた名前(たとえば)を使用して生成されたID(たとえばによって指定されたandroid:id="@+id/..My Str..)を取得できます。その場合、メソッドを使用するコードスニペットは次のようになります。RMy StrgetIdentifier()

public int getIdAssignedByR(Context pContext, String pIdString)
{
    // Get the Context's Resources and Package Name
    Resources resources = pContext.getResources();
    String packageName  = pContext.getPackageName();

    // Determine the result and return it
    int result = resources.getIdentifier(pIdString, "id", packageName);
    return result;
}

内からの Activity使用例findViewByIdは次のとおりです。

// Get the View (e.g. a TextView) which has the Layout ID of "UserInput"
int rID = getIdAssignedByR(this, "UserInput")
TextView userTextView = (TextView) findViewById(rID);


0

テーブルレイアウト(TableLayout)を更新するために、私は上記の再帰的なアプローチを使用してすべての子の子などを取得する必要がありました。

LinearLayoutとそれから拡張されたTableLayoutなどのクラスを使用するだけでよいので、状況は多少単純化されました。そして、私はTextViewの子供を見つけることにのみ興味がありました。しかし、私はそれがこの質問にまだ当てはまると思います。

最後のクラスは別のスレッドとして実行されます。つまり、子の解析前にバックグラウンドで他のことを実行できます。コードは小さくてシンプルで、githubにあります:https : //github.com/jkincali/Android-LinearLayout-Parser


0

このメソッドは、レイアウト内のすべてのビューを取得します。これは、Alexander Kulyakhtinの回答に似ています。違いは、すべてのタイプの親レイアウトを受け入れ、ビューの配列リストを返すことです。

public List<View> getAllViews(ViewGroup layout){
        List<View> views = new ArrayList<>();
        for(int i =0; i< layout.getChildCount(); i++){
            views.add(layout.getChildAt(i));
        }
        return views;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.