Question

I have two views, lets say A and B. I want A to be placed above B vertically, but center-aligned with B horizontaly, i.e. I want to achieve this:

enter image description here

I tried:

RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
    viewA.getLayoutParams();
layoutParams.addRule(
    RelativeLayout.ABOVE,
    viewB.getId()
);

But apparently what it did is placing A vertically above B, but horizontally floating to the left (aligned with X's left)

Please help.

Was it helpful?

Solution

What you have is on the right path, but you need to also add a rule for the horizontal centering: layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);

I recognize that this doesn't quite do what you asked in that it is specifying that you center in the parent view horizontally as opposed to specifying that you align the horizontal centers of A and B, but there isn't a direct way to do the latter with a RelativeLayout rule. (There are many indirect ways to do it instead.)


Addition:
Given that your view A is not centered horizontally in the parent, here's a suggestion. I don't know of a great / non-hacky way to do this, but I think that since RelativeLayout rules are applied during the measurement pass, you can use the left (and right) coordinates of view A after measurement is done to set the (public) left and right properties of view B to what they need to be in order to center the view under A.

So for example, if your parent view is a custom extension of View you can override its onMeasure() method, call like:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    // So that mA.left and mA.right first get set...
    mB.left = BWIDTH - (mA.left + mA.right) / 2;
    mB.right = mB.left + BWIDTH;
    /* You probably will need to re-measure (i.e., call super.onMeasure() again here)
     * if you need to get views X and Y to the left of view B or if  
     * if view B exceeds the previously-measured size... */
}

And if not, you can use setOnLayoutChangeListener() on the parent and a callback to achieve the same thing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top