3

I am making a Custom Layout Android component by extending abstract class ViewGroup (as per this video tutorial by Romain Guy on Parleys.com : http://www.parleys.com/#st=5&id=2191&sl=1).

My component should contain children, but I want to restrain that to only 1 child, of type ViewGroup as well (such as another LinearLayout or a RelativeLayout). Kindof like the ScrollView. Is there a way to add that restriction?

EDIT: Final solution as android developer said, is to programatically check the constraints onFinishInflate of the ViewGroup subclass as such:

@Override
public void onFinishInflate()
{
    if (getChildCount() > 1)
        throw new IllegalArgumentException("Only 1 child allowed");

    if (getChildCount() == 0 || !(getChildAt(0) instanceof ViewGroup))
        throw new IllegalArgumentException("Child must be a ViewGroup");
}
Francois Zard
  • 341
  • 3
  • 11
  • 2
    Semantically, I think an `IllegalStateException` would be more appropriate than `IllegalArgumentException`. But thanks for making this an easy websearch. – Michael Scheper Mar 03 '14 at 00:26
  • Also, the View class' docs imply there's a policy that mandates calling superclass implementation (`super.onFinishInflate()`), even though it currently doesn't do anything. See http://developer.android.com/reference/android/view/View.html#onFinishInflate%28%29 – Michael Scheper Mar 03 '14 at 01:53

2 Answers2

3

sure you can .

simply get the child count by using getChildCount() in order to check that there is only a single child.

then, get the only child there is in the viewGroup by using getChildAt(0) .

after this , use reflection on the result and do whatever extra checks you wish to do on its class (for example , use getSuperclass()

android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • I need this to happen in XML, not in code. Just like the ScrollView component. – Francois Zard Aug 11 '12 at 20:46
  • it doesn't matter . in xml , you (usually) only use the view . in the code ,you write its logic .ScrollView also has code... – android developer Aug 11 '12 at 20:46
  • Consider this example: In the XML layout, if I add my Custom ViewGroup and try to add 2 children to it, I want the compiler to complain. Just like ScrollView. Is this feasible? – Francois Zard Aug 11 '12 at 20:49
  • how do you intend on showing warnings? by throwing an exception? – android developer Aug 11 '12 at 21:32
  • Yes, i ended up throwing exceptions from onFinishInflate if any of the children don't match my restrictions. The exception will be thrown at runtime. – Francois Zard Aug 11 '12 at 21:51
  • nice. btw , if you are new to custom views , here's a tiny tip: you can use isInEditMode() if you wish to put some fake content in order to show how the view looks like . this could be useful if it takes a lot of time to get the content of the view (for example getting something from the internet) . – android developer Aug 11 '12 at 22:04
1

Let me add to this the answer to this question for everyone else starting with custom view group.

When views are added to a view group of any kind, the methods that could be used are the following:

public void addView(View child)
public void addView(View child, int index)
public void addView(View child, int width, int height)
public void addView(View child, LayoutParams params)
public void addView(View child, int index, LayoutParams params)

Regardless whether the ViewGroup and its children is added through xml or code, one of these methods would be called.

Now if you want to restrict your custom viewgroup to a certain condition. Simply add that condition in those methods.

Here's an example code taken from ScrollView Class.

@Override
public void addView(View child) {
    if (getChildCount() > 0) {
        throw new IllegalStateException("ScrollView can host only one direct child");
    }

    super.addView(child);
}

@Override
public void addView(View child, int index) {
    if (getChildCount() > 0) {
        throw new IllegalStateException("ScrollView can host only one direct child");
    }

    super.addView(child, index);
}

@Override
public void addView(View child, ViewGroup.LayoutParams params) {
    if (getChildCount() > 0) {
        throw new IllegalStateException("ScrollView can host only one direct child");
    }

    super.addView(child, params);
}

@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
    if (getChildCount() > 0) {
        throw new IllegalStateException("ScrollView can host only one direct child");
    }

    super.addView(child, index, params);
}

Tip: When looking for certain implementation, you may go look for how android components implement things and implement that as a guide. :)

Archie G. Quiñones
  • 11,638
  • 18
  • 65
  • 107
  • In your if conditions isn't it suppose to be checking for > 1? Otherwise the exception message does not make sense since it states that it only hosts one direct child, but the if condition will be true for any child count that is bigger than 0, including one direct child. – Shadow Mar 21 '19 at 17:12
  • @Shadow you actually got me think there for a sec. I just realized I took that entire block of code from the Android `ScrollView` Class. So I guess its working since `ScrollView` doesn't have that problem. You could go ahead and look at it yourself and figure out why its coded that way :) – Archie G. Quiñones Mar 22 '19 at 01:49
  • 1
    I see what is going on, it is doing the count check BEFORE calling super, that means whenever it is going to add the first child the count is 0. After adding the first child and a second one is added the count will already be 1, which is the max. So the code is absolutely correct, I was mistaken due to the super call order being made after the child count was checked. Your code is absolutely correct, even if it was copied. – Shadow Mar 22 '19 at 13:04