0

I'd like to place a view on top of an existing view. The view I'm targeting is inside a LinearLayout, which resides in a FrameLayout.

I'm thinking there's a way to do this with RelativeLayout because I already have it partially working. I'd like to align the new view to the bottom-left or top-left (as the origin) and then offset X and Y to some precise value that I specify.

How can this be achieved?

Here's the idea:

public static void placeTextRelativeToBottomLeftOfViewAtXY(final FrameLayout layout, View component, int x, int y, String text) {

    final TextView textView = new TextView(getContext());
    textView.setId((int)System.currentTimeMillis());
    final RelativeLayout relativeLayout = new RelativeLayout(getContext());
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
    params.setMargins(x, y, 0,0);
    params.addRule(RelativeLayout.LEFT_OF, component.getId());
    relativeLayout.setLayoutParams(params);
    relativeLayout.setBackgroundColor(Color.TRANSPARENT);
    textView.setText("+500 points!");
    textView.bringToFront();
    relativeLayout.addView(textView, params);
    layout.addView(relativeLayout);
}
Onik
  • 19,396
  • 14
  • 68
  • 91
Mike
  • 609
  • 12
  • 36
  • My view of this is that the layout should not matter at all. I'm trying to design this code so that the text is added in some new layout (in the case of this function, a RelativeLayout). Initially, I just wanted to use AbsoluteLayout, but am avoiding that since it's deprecated. The inputs suggest the goal: given a FrameLayout, add text at XY relative to the bottom left of View component (input). The code is probably conceptually wrong. – Mike Sep 30 '18 at 13:37
  • Thanks for the generateViewId() - changed to that! To add to my last comment - since the root is a FrameLayout - overlapping is allowed. So the layout chosen for the overlap could just as well have been AbsoluteLayout - all that matters is that I'm placing the text at XY relative to some child of FrameLayout (the input View component). – Mike Sep 30 '18 at 13:41
  • That's what I thought since it wasn't working. Any idea how I can do this? Am I forced to figure out what XY should be and just use AbsoluteLayout? – Mike Sep 30 '18 at 13:48

1 Answers1

1

Based on the additional information in comments, even if it is possible to overlap a different layouts inside a FrameLayout, those layouts will only be able to position their own children. A RelativeLayout won't be able to position one of its child views relative to a view in a different sibling or parent Layout.

The way to go would be to flattern the heierarchy of Layouts, setting the root layout to a RelativeLayout or a ConstraintLayout.

ConstraintLayout is more flexible in terms of positioning views, but it is also more difficult to learn.

Here I am leaving an alternative to be used with RelativeLayout as the root view. The important items to look at are the setting of the LayoutParams which is sometimes a bit confussing.
The LayoutParams are set on the child view, but the class used depends on the parent view.

Also take in mind that to keep margins display independent you need to convert dp into pixels (for the sake of simplicity I haven't done that, but there are examples of how to do this here in SO).

It also uses View.generteViewId() go get an id for a view created dynamically.

To make it simple I included the reference View in the xml, but i could have also been created dynamically.

Layout

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rlContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tvCenterText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Texto estatico"
        android:layout_centerInParent="true"/>

</RelativeLayout>

Main Activity

public class DynamicViewsActivity extends AppCompatActivity {

    RelativeLayout rlContainer;
    TextView centerText;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dynamicviews);

        rlContainer = findViewById(R.id.rlContainer);

        centerText = findViewById(R.id.tvCenterText);


        placeTextRelativeToBottomLeftOfViewAtXY(rlContainer, centerText, 100,10, "Hola");

    }

    public void placeTextRelativeToBottomLeftOfViewAtXY(final RelativeLayout layout, View component, int x, int y, String text) {

        final TextView textView = new TextView(this);
        textView.setId(View.generateViewId());
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        params.setMargins(x, y, x,y);
        params.addRule(RelativeLayout.LEFT_OF, component.getId());
        params.addRule(RelativeLayout.ALIGN_BASELINE, component.getId());
        textView.setLayoutParams(params);
        textView.setText(text);
        layout.addView(textView);
    }
}
Juan
  • 5,525
  • 2
  • 15
  • 26
  • I need to use FrameLayout as the root layout because I'm switching views like a card deck. Can RelativeLayout do that too? – Mike Sep 30 '18 at 14:31
  • Of course, I can keep the frameLayout and pass in the relativeLayout! Thanks so much for your help Juan! – Mike Sep 30 '18 at 14:34
  • I added a paragraph regarding margins and any other meassure you would normally set in dp – Juan Sep 30 '18 at 14:43
  • Juan, would you mind elaborating on what you said about keeping margin display independent? I understand the difference between device independent pixels (dp) and pixels, but I don't understand what you are saying here. – Mike Sep 30 '18 at 16:36
  • in params.setMargins(x,y,x,y), x and y are int in pixels. In your program if specify the margins in dp, those dp have to be converted to pixels to be passed as x, and y to the unction. The conversion is device dependant. At runtime you need to get the DisplayMetrics if I remember correctly. There are questions in SO on how to do the conversion. https://stackoverflow.com/questions/8295986/how-to-calculate-dp-from-pixels-in-android-programmatically – Juan Sep 30 '18 at 17:28