Установить абсолютное положение вида

Можно ли установить абсолютную позицию представления в Android? (Я знаю, что есть AbsoluteLayout, но он устарел ...)

Например, если у меня экран 240x320 пикселей, как я могу добавить ImageView, который имеет размер 20x20 пикселей, чтобы его центр находился в позиции (100,100)?


person Sephy    schedule 20.07.2010    source источник
comment
также см. view.setTranslationX() или view.offsetLeftAndRight()   -  person Drew LeSueur    schedule 20.01.2013
comment
Я только что выпустил библиотеку, которая могла бы вас заинтересовать. github.com/ManuelPeinado/ImageLayout   -  person Manuel    schedule 18.04.2013
comment
Это так сложно, потому что в 99,9% случаев абсолютное позиционирование на Android - плохая идея. Если вы пишете приложение, которое будет ТОЛЬКО когда-либо запускаться на одном физическом устройстве, это может сработать, но, как правило, делать такое предположение небезопасно. Например, не загружайте это в Google Play. Он отлично работает на iOS, потому что есть только несколько аппаратных устройств, и вы можете создать собственную раскадровку для каждого из них.   -  person edthethird    schedule 07.01.2015
comment
@edthethird, В моем кроссплатформенном приложении я получаю размер экрана и все основываю на нем. Я только что перешел на устаревший AbsoluteLayout, и он отлично работает.   -  person William Jockusch    schedule 07.01.2015
comment
честно, но это то, что Relative Layout или LinearLayout сделает за вас автоматически.   -  person edthethird    schedule 15.01.2015
comment
Почему AbsoluteLayout устарел? Конечно, необходимость размещать виджеты в точных положениях для определенных приложений никуда не делась!   -  person Paul McCarthy    schedule 26.04.2017


Ответы (8)


Вы можете использовать RelativeLayout. Допустим, вам нужен ImageView размером 30x40 в позиции (50,60) внутри вашего макета. Где-то в вашей деятельности:

// 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);

Еще примеры:

Помещает два ImageView 30x40 (один желтый, один красный) в (50,60) и (80,90) соответственно:

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);

Помещает один желтый ImageView 30x40 в (50,60), а другой 30x40 красный ImageView ‹80,90> относительно желтого 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);
person Andy Zhang    schedule 20.07.2010
comment
Я попробую сегодня вечером, это довольно хорошая идея, не знаю, почему я не подумал об этом. Поскольку у меня есть несколько ImageView, не лучше ли использовать FrameLayout? - person Sephy; 21.07.2010
comment
Действительно, похоже, что это работает, однако это работает только при добавлении одного изображения таким образом. если я попытаюсь добавить второй, первый просто исчезнет ... - person Sephy; 22.07.2010
comment
Два изображения находятся друг над другом. Я добавлю код к своему решению выше, чтобы объяснить. - person Andy Zhang; 22.07.2010
comment
Да, действительно, вчера я тоже это обнаружил, самостоятельно раскопав ваше решение. Я также пробую использовать FrameLayout. Моя актуальная проблема заключается в том, что у меня есть 5 изображений, каждое из которых имеет случайную позицию (x, y), поэтому я не могу использовать RelativeLayout.RIGHT_OF или что-то в этом роде. Странно то, что я могу получить 3 изображения, которые нужно разместить правильно, но 2 из них не работают ... Я не понимаю ... Я обновлю свой пост, добавив несколько снимков экрана сегодня вечером и немного кода. - person Sephy; 23.07.2010
comment
Вышеупомянутый метод в значительной степени делает то же самое, что и абсолютное положение. Если у вас есть другие проблемы, я буду рад помочь! - person Andy Zhang; 27.02.2011
comment
Почему использование этого метода может быть лучше, чем использование AbsoluteLayout? Просто потому, что AbsoluteLayout устарел? - person Nathan; 01.10.2011
comment
@sephy для вашей ситуации вы можете настроить каждое представление на parentleft и parentTop = true, а также установив положение x, y на leftmargin и topmargin соответственно. - person KumailR; 01.02.2014
comment
абсолютный макет устарел из-за разных размеров экрана. но с некоторыми вычислениями мы можем использовать абсолютные значения, чтобы проверить, звучит ли одно представление справа, слева, сверху, снизу другого представления, но для ширины и высоты сложно; таким образом мы можем реализовать абсолютное поведение с помощью relativelayout. - person KumailR; 01.02.2014

Как правило, вы можете добавить представление в определенной позиции, используя FrameLayout в качестве контейнера, указав атрибуты leftMargin и topMargin.

В следующем примере ImageView размером 20x20 пикселей будет размещаться в позиции (100200) с использованием FrameLayout в качестве полноэкранного контейнера:

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>

Действие / Фрагмент / Пользовательское представление

//...
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);
//...

Это поможет, потому что поля можно использовать как абсолютные (X, Y) координаты без RelativeLayout:

введите описание изображения здесь

person bonnyz    schedule 07.01.2015
comment
Блестяще! Стоит 500! +1 - person Lisa Anne; 13.02.2016

Просто чтобы добавить к ответу Энди Чжана выше, если вы хотите, вы можете указать параметр для rl.addView, а затем внести в него изменения позже, поэтому:

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

С равным успехом может быть записано как:

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

Поэтому, если вы сохраните переменную params, вы можете изменить макет iv в любое время после добавления ее в rl.

person Excrubulent    schedule 19.01.2012
comment
очень понравился этот образец. Можете ли вы предложить мне, как я могу установить оси x, y, когда у меня есть изображение в макете xml. (Я пытаюсь изменить размер изображения, и мне нужно установить изображение в каком-то положении) - person G_S; 21.08.2012
comment
Боюсь, я не совсем понимаю, о чем вы спрашиваете. Вы пытаетесь получить доступ к объекту LayoutParams, связанному с объектом, который был размещен с помощью макета XML? Не знаю, как это делается. Возможно, стоит задать новый вопрос, чтобы получить на него ответ, если вы не можете найти ответ в другом месте. - person Excrubulent; 23.08.2012
comment
взгляните на этот вопрос stackoverflow.com/questions/12028404/ - person G_S; 23.08.2012

Более чистый и динамичный способ без жесткого кодирования значений пикселей в коде.

Я хотел разместить диалоговое окно (которое я надуваю на лету) точно под нажатой кнопкой.

и решил это так:

    // 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;
    }

Однако вы должны убедиться, что родительский макет myView является экземпляром RelativeLayout.

более полный код:

    // 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;
    }

Таким образом, вы по-прежнему можете ожидать, что целевое представление будет адаптироваться к любым параметрам макета, установленным с помощью XML-файлов макета, вместо жесткого кодирования этих пикселей / dps в вашем коде Java.

person Hari Krishna Ganji    schedule 31.07.2012

Проверить снимок экрана

Разместите любой вид на нужную вам точку X и Y

файл макета

<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

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);
    }
}

Готово

person Hiren Patel    schedule 02.06.2015

На всякий случай, если это может кому-то помочь, вы также можете попробовать этот аниматор ViewPropertyAnimator как показано ниже

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

myView.animate().translateX(pixelInScreen) 

Примечание. Этот пиксель не относится к виду. Этот пиксель - позиция пикселя на экране.

кредиты на ответ bpr10

person praveenb    schedule 26.07.2017

Попробуйте следующий код, чтобы установить просмотр в определенном месте: -

            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);
person duggu    schedule 17.09.2015

Мой код для Xamarin, я использую для этой цели FrameLayout, и следующий мой код:

               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;
                    }

            }

        }

Это было полезно для меня, потому что мне нужно, чтобы свойство представления перекрывало друг друга на основе их внешнего вида, например, представления накладываются друг на друга.

person Technacron    schedule 06.11.2016