Set the absolute position of a view
Asked Answered
S

8

196

Is it possible to set the absolute position of a view in Android? (I know that there is an AbsoluteLayout, but it's deprecated...)

For example, if I have a 240x320px screen, how could I add an ImageView which is 20x20px such that its center is at the position (100,100)?

Sirajuddaula answered 20/7, 2010 at 21:40 Comment(6)
also see view.setTranslationX() or view.offsetLeftAndRight()Supersensual
I've just released a library that may have been of interest here. github.com/ManuelPeinado/ImageLayoutBatholith
This is so difficult because 99.9% of the time absolute positioning is a bad idea on android. If you are writing an app that will ONLY ever be run on one physical device, then this might work, but that is generally not a safe assumption to make. For example, do not upload this to google play. It works fine on iOS because there are only a handful of hardware devices, and you can build a custom storyboard for each one.Phebephedra
@edthethird, In my cross-platform app, I get the screen size and base everything on that. I just switched over to the "obsolete" AbsoluteLayout, and it works fine.Featly
fair enough, but that's what a Relative Layout or LinearLayout will do for you automatically.Phebephedra
Why was AbsoluteLayout deprecated? Surely the need to place widgets in exact positions for certain apps has not gone away!Rriocard
C
286

You can use RelativeLayout. Let's say you wanted a 30x40 ImageView at position (50,60) inside your layout. Somewhere in your activity:

// Some existing RelativeLayout from your layout xml
RelativeLayout rl = (RelativeLayout) findViewById(R.id.my_relative_layout);

ImageView iv = new ImageView(this);

RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(30, 40);
params.leftMargin = 50;
params.topMargin = 60;
rl.addView(iv, params);

More examples:

Places two 30x40 ImageViews (one yellow, one red) at (50,60) and (80,90), respectively:

RelativeLayout rl = (RelativeLayout) findViewById(R.id.my_relative_layout);
ImageView iv;
RelativeLayout.LayoutParams params;

iv = new ImageView(this);
iv.setBackgroundColor(Color.YELLOW);
params = new RelativeLayout.LayoutParams(30, 40);
params.leftMargin = 50;
params.topMargin = 60;
rl.addView(iv, params);

iv = new ImageView(this);
iv.setBackgroundColor(Color.RED);
params = new RelativeLayout.LayoutParams(30, 40);
params.leftMargin = 80;
params.topMargin = 90;
rl.addView(iv, params);

Places one 30x40 yellow ImageView at (50,60) and another 30x40 red ImageView <80,90> relative to the yellow ImageView:

RelativeLayout rl = (RelativeLayout) findViewById(R.id.my_relative_layout);
ImageView iv;
RelativeLayout.LayoutParams params;

int yellow_iv_id = 123; // Some arbitrary ID value.

iv = new ImageView(this);
iv.setId(yellow_iv_id);
iv.setBackgroundColor(Color.YELLOW);
params = new RelativeLayout.LayoutParams(30, 40);
params.leftMargin = 50;
params.topMargin = 60;
rl.addView(iv, params);

iv = new ImageView(this);
iv.setBackgroundColor(Color.RED);
params = new RelativeLayout.LayoutParams(30, 40);
params.leftMargin = 80;
params.topMargin = 90;

// This line defines how params.leftMargin and params.topMargin are interpreted.
// In this case, "<80,90>" means <80,90> to the right of the yellow ImageView.
params.addRule(RelativeLayout.RIGHT_OF, yellow_iv_id);

rl.addView(iv, params);
Cockroach answered 20/7, 2010 at 22:58 Comment(8)
I'll have a go at that tonight, that's a pretty nice idea, don't know why I didn't think about that. As I have several ImageView to put, wouldn't it be better to use a FrameLayout?Sirajuddaula
Indeed this seems to work, however, it's only working when a add one picture this way. if I try to add a 2nd one, the first one just vanishes...Sirajuddaula
The two images are just on top of each other. I will add some code to my solution above to explain.Cockroach
Yeah indeed, i found that yesterday too by digging your solution on my own. I also try stuff with the FrameLayout. My actual issue is that I have 5 images with each a random (x,y) position, so I can't use RelativeLayout.RIGHT_OF or something like that. The strange thing is that i can get 3 images to be placed properly but 2 of them aren't working...I don't understand... I'll update my post with some screenshots tonight and some code.Sirajuddaula
The above method pretty much does the same thing as absolute position. If you have any other concerns, I'd be happy to help!Cockroach
Why would using this method be any better than using AbsoluteLayout? Just because AbsoluteLayout is deprecated?Unfortunate
@sephy for your situation you can have your each view set to parentleft and parentTop = true, and by setting x, y position to leftmargin and topmargin respectively.Sardinia
absolute layout is deprecated as because of different screen sizes. but with some calculation we can use absolute values to check whether one view on right,left,top,bottom of other view but for width and height sounds complicated; this way we can implement absolute behavior using relativelayout.Sardinia
S
78

In general, you can add a View in a specific position using a FrameLayout as container by specifying the leftMargin and topMargin attributes.

The following example will place a 20x20px ImageView at position (100,200) using a FrameLayout as fullscreen container:

XML

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:background="#33AAFF"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</FrameLayout>

Activity / Fragment / Custom view

//...
FrameLayout root = (FrameLayout)findViewById(R.id.root);
ImageView img = new ImageView(this);
img.setBackgroundColor(Color.RED);
//..load something inside the ImageView, we just set the background color

FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(20, 20);
params.leftMargin = 100;
params.topMargin  = 200;
root.addView(img, params);
//...

This will do the trick because margins can be used as absolute (X,Y) coordinates without a RelativeLayout:

enter image description here

Spinel answered 7/1, 2015 at 17:15 Comment(0)
P
18

Just to add to Andy Zhang's answer above, if you want to, you can give param to rl.addView, then make changes to it later, so:

params = new RelativeLayout.LayoutParams(30, 40);
params.leftMargin = 50;
params.topMargin = 60;
rl.addView(iv, params);

Could equally well be written as:

params = new RelativeLayout.LayoutParams(30, 40);
rl.addView(iv, params);
params.leftMargin = 50;
params.topMargin = 60;

So if you retain the params variable, you can change the layout of iv at any time after adding it to rl.

Papaverine answered 19/1, 2012 at 3:2 Comment(3)
loved this sample. Can you suggest me how can i set the x,y axis when i am having the image in the xml layout.(i am trying to resize the image and i need to set the image at some position)Harrisharrisburg
I'm afraid I don't quite understand what you're asking. Are you trying to access the LayoutParams object associated with an object that has been positioned using the XML layout? I'm not sure how that's done. It might be worth setting up a new question to have this answered, if you can't find the answer elsewhere.Papaverine
please have a look at this question #12028904Harrisharrisburg
D
5

A more cleaner and dynamic way without hardcoding any pixel values in the code.

I wanted to position a dialog (which I inflate on the fly) exactly below a clicked button.

and solved it this way :

    // get the yoffset of the position where your View has to be placed 
    final int yoffset = < calculate the position of the view >

    // position using top margin
    if(myView.getLayoutParams() instanceof MarginLayoutParams) {
        ((MarginLayoutParams) myView.getLayoutParams()).topMargin = yOffset;
    }

However you have to make sure the parent layout of myView is an instance of RelativeLayout.

more complete code :

    // identify the button
    final Button clickedButton = <... code to find the button here ...>

    // inflate the dialog - the following style preserves xml layout params
    final View floatingDialog = 
        this.getLayoutInflater().inflate(R.layout.floating_dialog,
            this.floatingDialogContainer, false);

    this.floatingDialogContainer.addView(floatingDialog);

    // get the buttons position
    final int[] buttonPos = new int[2];
    clickedButton.getLocationOnScreen(buttonPos);        
    final int yOffset =  buttonPos[1] + clickedButton.getHeight();

    // position using top margin
    if(floatingDialog.getLayoutParams() instanceof MarginLayoutParams) {
        ((MarginLayoutParams) floatingDialog.getLayoutParams()).topMargin = yOffset;
    }

This way you can still expect the target view to adjust to any layout parameters set using layout XML files, instead of hardcoding those pixels/dps in your Java code.

Dorseydorsiferous answered 31/7, 2012 at 14:8 Comment(0)
S
0

Check screenshot

Place any view on your desire X & Y point

layout file

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.test.MainActivity" >

    <AbsoluteLayout
        android:id="@+id/absolute"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <RelativeLayout
            android:id="@+id/rlParent"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <ImageView
                android:id="@+id/img"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/btn_blue_matte" />
        </RelativeLayout>
    </AbsoluteLayout>

</RelativeLayout>

Java Class

public class MainActivity extends Activity {

    private RelativeLayout rlParent;
    private int width = 100, height = 150, x = 20, y= 50; 

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

        AbsoluteLayout.LayoutParams param = new AbsoluteLayout.LayoutParams(width, height, x, y);
        rlParent = (RelativeLayout)findViewById(R.id.rlParent);
        rlParent.setLayoutParams(param);
    }
}

Done

Standpoint answered 2/6, 2015 at 4:25 Comment(0)
G
0

Just in case it may help somebody, you may also try this animator ViewPropertyAnimator as below

myView.animate().x(50f).y(100f);

myView.animate().translateX(pixelInScreen) 

Note: This pixel is not relative to the view. This pixel is the pixel position in the screen.

credits to bpr10 answer

Guileful answered 26/7, 2017 at 10:25 Comment(0)
A
-1

Try below code to set view on specific location :-

            TextView textView = new TextView(getActivity());
            textView.setId(R.id.overflowCount);
            textView.setText(count + "");
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
            textView.setTextColor(getActivity().getResources().getColor(R.color.white));
            textView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // to handle click 
                }
            });
            // set background 
            textView.setBackgroundResource(R.drawable.overflow_menu_badge_bg);

            // set apear

            textView.animate()
                    .scaleXBy(.15f)
                    .scaleYBy(.15f)
                    .setDuration(700)
                    .alpha(1)
                    .setInterpolator(new BounceInterpolator()).start();
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT);
            layoutParams.topMargin = 100; // margin in pixels, not dps
            layoutParams.leftMargin = 100; // margin in pixels, not dps
            textView.setLayoutParams(layoutParams);

            // add into my parent view
            mainFrameLaout.addView(textView);
Aparejo answered 17/9, 2015 at 9:16 Comment(0)
M
-3

My code for Xamarin, I am using FrameLayout for this purpose and following is my code:

               List<object> content = new List<object>();

        object aWebView = new {ContentType="web",Width="300", Height = "300",X="10",Y="30",ContentUrl="http://www.google.com" };
        content.Add(aWebView);
        object aWebView2 = new { ContentType = "image", Width = "300", Height = "300", X = "20", Y = "40", ContentUrl = "https://www.nasa.gov/sites/default/files/styles/image_card_4x3_ratio/public/thumbnails/image/leisa_christmas_false_color.png?itok=Jxf0IlS4" };
        content.Add(aWebView2);
        FrameLayout myLayout = (FrameLayout)FindViewById(Resource.Id.frameLayout1);
        foreach (object item in content)
        {

            string contentType = item.GetType().GetProperty("ContentType").GetValue(item, null).ToString();
            FrameLayout.LayoutParams param = new FrameLayout.LayoutParams(Convert.ToInt32(item.GetType().GetProperty("Width").GetValue(item, null).ToString()), Convert.ToInt32(item.GetType().GetProperty("Height").GetValue(item, null).ToString()));
            param.LeftMargin = Convert.ToInt32(item.GetType().GetProperty("X").GetValue(item, null).ToString());
            param.TopMargin = Convert.ToInt32(item.GetType().GetProperty("Y").GetValue(item, null).ToString());

            switch (contentType) {
                case "web":{
                        WebView webview = new WebView(this);

                        //webview.hei;
                        myLayout.AddView(webview, param);
                        webview.SetWebViewClient(new WebViewClient());
                        webview.LoadUrl(item.GetType().GetProperty("ContentUrl").GetValue(item, null).ToString());

                        break;
                    }
                case "image":
                    {
                        ImageView imageview = new ImageView(this);

                        //webview.hei;
                        myLayout.AddView(imageview, param);
                        var imageBitmap =  GetImageBitmapFromUrl("https://www.nasa.gov/sites/default/files/styles/image_card_4x3_ratio/public/thumbnails/image/leisa_christmas_false_color.png?itok=Jxf0IlS4");
                        imageview.SetImageBitmap(imageBitmap);


                        break;
                    }

            }

        }

It was useful for me because I needed the property of view to overlap each other on basis of their appearance, e.g the views get stacked one above other.

Merous answered 6/11, 2016 at 7:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.