Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RelativeLayout: align view to child of sibling viewgroup

I'm trying to make a tab bar in android using a RelativeLayout and a RadioGroup that has an indicator which will slide to indicate the active RadioButton within the RadioGroup.

These are customized radio buttons that are effectively rectangles with an icon over text, all contents centered, which uses a custom state-selector for the background.

Here's my current hierarchy:

<RelativeLayout>       // Main view of the tab bar
  <RadioGroup>         // The buttons
    <RadioButton />
    <RadioButton />
    <RadioButton />
  </RadioGroup>
  <ImageView />        // The indicator
</RelativeLayout>

The idea I had was when a radio button was clicked, I would align the indicator to the top & bottom of the selected radio button (and animate it). However, It seems that layout_align<Edge> only works with sibling elements, not with members of another view group, i.e. I can align to the RadioGroup itself, but not to a RadioButton inside it.

I thought of putting the indicator as a member of the RadioGroup, but since RadioGroup is an extension of LinearLayout, there doesn't seem to be a way to place it at the edge of a given RadioButton.

Can anyone think of how I might solve this issue? Or perhaps there's a better solution than my animate-align-to-button technique?

UPDATE With @superjos help, I managed to work this out fairly well.

I had to give each button a known height instead of using wrap_content (not ideal, but for this project it should probably work fine). Make the indicator height match that of the buttons. Make sure the RadioGroup is set to wrap content and be centered vertically in the parent view. Set indicator to alignTop and toRightOf the RadioGroup. Then, for the button click listener:

int prevY, newY;
int prevButtonIndex, newButtonIndex;

public void moveIndicator(button, indicator, index) {
  prevY = newY;
  newY = prevY + (index - prevButtonIndex) * button.getHeight();
  TranslateAnimation animation = new TranslateAnimation(0, 0, prevY, newY);
  animation.setDuration(500);
  animation.setFillAfter(true); // stay at final animation position
  indicator.setAnimation();
  animation.start();
}
like image 804
Josh Kovach Avatar asked Nov 18 '11 19:11

Josh Kovach


1 Answers

Here's my idea about it. Following are some more detailed steps.

The idea is to have the ImageView has a RadioGroup sibling, as it is in your sample. The ImageView is initially positioned on the right of the RadioGroup, and its horizontal middle line is aligned with the one of the first (or whatever chosen) RadioButton.

Then, upon a RadioButton click, a TranslateAnimation is built/configured at runtime in order to let the ImageView shift vertically until its middle line gets aligned with the one of the clicked button. The animation is set with fillAfter so to stay firm after it completes.

Steps:

  • Create your resources so that ImageView and RadioButtons have the same height, or else work with vertical paddings so that they result having the same height.

  • To initially align the ImageView to the first RadioButton, some XML could suffice: in ImageView attach layout_toRightOf and layout_alignTop to the RadioGroup. In order to take into account the top-padding from RadioGroup, you could add that to the initial ImageView top-padding XML attribute. Or better as top-margin.

  • When a RadioButton is clicked, create a TranslateAnimation that will be applied to the ImageVew, changing only the Y coordinate starting from 0 to its destination toY value (while from/toX attribute will be 0). That is given by a formula such as:

    toY = (ClickedRadioButton.Index - LastClickedRadioButton.Index) * RadioButton.Heigth
    

    Here Index is the ordinal position of the RadioButton within the group (e.g. from 0 to 2) (Warning: that is pseudo-code, not necessarily an existing Java field named Index).

  • Apply the animation to the ImageView and start it.

like image 67
superjos Avatar answered Oct 05 '22 23:10

superjos