0

I would like to reproduce the following UI in my Android app but I have few questions.

  • I use a RelativeLayout
  • Each circle is an ImageView
  • Negative margin is used for CircleLeft and CircleRight

enter image description here

My attempt:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/CircleCenter"
        android:layout_marginTop="120dp"
        android:background="@drawable/CircleCenter"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/CircleLeft"
        android:background="@drawable/CircleLeft"
        android:layout_alignTop="@+id/CircleCenter"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="false"
        android:layout_marginLeft="-70dp"
        android:layout_marginTop="-20dp" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/CircleRight"
        android:background="@drawable/CircleRight"
        android:layout_alignTop="@+id/CircleCenter"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="false"
        android:layout_alignParentStart="false"
        android:layout_marginRight="-70dp"
        android:layout_marginTop="-20dp" />

</RelativeLayout>

Question

I think it's not so bad, but there is one problem: how to have auto negative margin (with something like: marginRight = -(ImageView width/2) ?

Thanks!

Guicara
  • 1,668
  • 2
  • 20
  • 34

2 Answers2

1

Programmatically :

RelativeLayout.LayoutParams paramsLeft = (RelativeLayout.LayoutParams) mCircleLeft.getLayoutParams();
paramsLeft.setMargins(mCircleLeft.getMeasuredWidth()/2, marginTop, 0, 0);
// do the same thing for the right image

EDIT : If getMeasuredWidth() is == 0 when you are executing the code, add a ViewTreeObserver, he is going to tell you when the view is rendered :

ViewTreeObserver vto = mCircleLeft.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
      @Override
      public void onGlobalLayout() {

     // execute the previous code here

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
           obs.removeOnGlobalLayoutListener(this);
      } else {
           obs.removeGlobalOnLayoutListener(this);
      }

    }
});
Andros
  • 4,069
  • 1
  • 22
  • 30
  • Indeed, imageViewLeft.`getMeasuredWidth()` return 0. Maybe it's because the `layout_width="wrap_content"` and `layout_width="wrap_content"`? What is `mWebview`? – Guicara Jan 03 '14 at 15:22
  • Sorry for the "mWebView", copy paste error ... I edited my answer. It should work with the ViewTreeObserver. – Andros Jan 03 '14 at 15:26
  • Few adjustments of your code in the edit of my question. But I valid your answer. Thanks! – Guicara Jan 03 '14 at 15:46
0

Solution #1 (based on @Andros)

We need to do that programmatically.

Note: You cannot use the width/height/getMeasuredWidth/getMeasuredHeight on a view before the system does not render it (typically from onCreate/onResume). So we need to use a ViewTreeObserver (code here).

View this example (I use RoboGuice to simplify the code):

import roboguice.inject.ContentView;
import roboguice.inject.InjectView;

@ContentView(R.layout.activity_foo)
public class FooActivity extends Activity {

    @InjectView(R.id.CircleLeft)
    private ImageView circleLeft;

    @InjectView(R.id.CircleCenter)
    private ImageView circleCenter;

    @InjectView(R.id.CircleRight)
    private ImageView circleRight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ViewTreeObserver vto = circleLeft.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                RelativeLayout.LayoutParams paramsLeft = (RelativeLayout.LayoutParams) circleLeft.getLayoutParams();
                paramsLeft.setMargins(-circleLeft.getMeasuredWidth()/2, -40, 0, 0);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    circleLeft.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                } else {
                    circleLeft.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
            }
        });

    }

}

It's not perfect because I have to create a new ViewTreeObserver for imageViewRight...

Maybe there is a more efficient way to do that?


Edit :

Solution #2

Instead of using ViewTreeObserverwe can use .post(new Runnable():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    cicleLeft.post(new Runnable() {
        @Override
        public void run() {
            RelativeLayout.LayoutParams paramsLeft = (RelativeLayout.LayoutParams) cicleLeft.getLayoutParams();
            paramsLeft.setMargins(-cicleLeft.getMeasuredWidth()/2, -40, 0, 0);
        }
    });
}
Community
  • 1
  • 1
Guicara
  • 1,668
  • 2
  • 20
  • 34