11

In my xml layouts I have a custom view in which i will put some children like:

<com.proj.layouts.components.ScrollLayout
    android:id="@+id/slBody"
    android:layout_width="700dp"
    android:layout_height="400dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="child1"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="child2"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="child3"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="child4"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="child5"/>
</com.proj.layouts.components.ScrollLayout>

Let me explain a bit more. I wrote a custom ScrollView in which I already have a container defined, for the children. So I just want to put them there.

public class ScrollLayout extends LinearLayout {
    // View responsible for the scrolling
    private FrameLayout svContainer;
    // View holding all of the children
    private LinearLayout llContainer;

    public ScrollLayout(Context context) {
        super(context);
        init();
    }

    public ScrollLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        super.removeAllViews(); // kill old containers


        svContainer = new HorizontalScroll(getContext());
        llContainer = new LinearLayout(getContext());
        llContainer.setOrientation(orientation);
        svContainer.addView(llContainer);

        svContainer.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        llContainer.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

        addView(svContainer);


    }

    ... I left out the part which takes care of the scroll event ...
}

What is the way to add Child* to llContainer?

sebataz
  • 1,025
  • 2
  • 11
  • 35

3 Answers3

11

Why don't you just add all the children to the LinearLayout from your ScrollLayout? This should be done in the onFinishInflate() method.

for (int i = 0; i<getChildCount(); i++)
{
    View v = getChildAt(i);
    removeViewAt(i);
    llContainer.addView(v);
}

When you write your structure in the XML file - all inner views are children of your custom layout. Just replace it to LinearLayout.

Lukasz 'Severiaan' Grela
  • 6,078
  • 7
  • 43
  • 79
Jin35
  • 8,602
  • 3
  • 32
  • 52
  • 1
    cause you call `super.removeAllViews();` - remove this string – Jin35 Feb 13 '12 at 13:02
  • the same without that line... could it be because I placed your code inside the `init()`? – sebataz Feb 13 '12 at 13:06
  • It should be in init() method. Can you provide your xml? – Jin35 Feb 13 '12 at 13:11
  • if placing inside `init()`: child count is 0, but if place it inside `onLayout()` it will show me one of the child view. I don't get it, do you have any idea on this behavior? – sebataz Feb 13 '12 at 13:29
  • 1
    try to do it in method `onFinishInflate()` – Jin35 Feb 13 '12 at 13:34
  • 1
    I suppose that when android starts inflating views it goes from parents to children - and when you are in constructor of custom view - children does not exist yet. – Jin35 Feb 13 '12 at 13:36
8

Jin35's answer has a serious problem: getChildCount() changes value over the iterations because we are removing the children.

This should be a better solution:

while (getChildCount() > 0) {
    View v = getChildAt(0);
    removeViewAt(0);
    llContainer.addView(v);
}
André Staltz
  • 13,304
  • 9
  • 48
  • 58
  • I get a `StackOverflowException` when I do this. – howettl May 22 '15 at 20:24
  • @howettl If you're getting a `StackOverflowException` chances are you did what I did and tried to move a view into one of its children. – GHC Apr 22 '16 at 06:46
5

I agree Jin35's answer is flawed. Also, the svContainer is added, so we cannot continue until getChildCount() == 0.

By the end of init(), getChildCount() == 1, since svContainer has been added but the TextViews have not. By the end of onFinishInflate(), the TextViews have been added and should be at positions 1, 2, 3, 4 and 5. But if you then remove the View at position 1, the indices of the others will all decrease by 1 (standard List behaviour).

I would suggest:

@Override
protected void onFinishInflate() {
    super.onFinishInflate();

    View v;
    while ((v = getChildAt(1)) != null) {
        removeView(v);
        llContainer.addView(v);
    }
}
Fletcher Johns
  • 1,236
  • 15
  • 20