Установить абсолютную позицию вида


180

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

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


3
также см. view.setTranslationX()илиview.offsetLeftAndRight()
Дрю Лезер

Я только что выпустил библиотеку, которая может быть интересна здесь. github.com/ManuelPeinado/ImageLayout
Мануэль

1
Это так сложно, потому что 99,9% времени абсолютного позиционирования это плохая идея на Android. Если вы пишете приложение, которое будет запускаться ТОЛЬКО на одном физическом устройстве, это может сработать, но это, как правило, небезопасное предположение. Например, не загружайте это в Google Play. Он отлично работает на iOS, потому что есть только несколько аппаратных устройств, и вы можете создать собственную раскадровку для каждого.
edthethird 3

2
@edthethird, в своем кроссплатформенном приложении я получаю размер экрана и все на этом основываю. Я просто переключился на «устаревший» AbsoluteLayout, и он отлично работает.
Уильям Джокуш

достаточно справедливо, но это то, что Relative Layout или LinearLayout сделает для вас автоматически.
edthethird

Ответы:


271

Вы можете использовать RelativeLayout. Допустим, вы хотели 30x40 ImageView в позиции (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);

Больше примеров:

Размещает два 30x40 ImageViews (один желтый, один красный) в (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);

Помещает один 30x40 желтый ImageView в (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);

1
Я пойду сегодня вечером, это довольно хорошая идея, не знаю, почему я не подумал об этом. Поскольку у меня есть несколько, ImageViewчтобы положить, не лучше ли будет использовать FrameLayout?
Сефи

На самом деле это, кажется, работает, однако, это работает, только если добавить одну картинку таким образом. если я попытаюсь добавить второй, первый просто исчезнет ...
Сефи

1
Два изображения просто друг на друга. Я добавлю некоторый код в моё решение выше, чтобы объяснить.
Энди Чжан

2
Да, действительно, я обнаружил это и вчера, выкопав ваше решение самостоятельно. Я также пробую вещи с FrameLayout. Моя настоящая проблема заключается в том, что у меня есть 5 изображений с каждой случайной (x, y) позицией, поэтому я не могу использовать RelativeLayout.RIGHT_OF или что-то подобное. Странно то, что я могу получить 3 изображения для правильного размещения, но 2 из них не работают ... Я не понимаю ... Сегодня вечером я обновлю свой пост несколькими скриншотами и кодом.
Сефи

9
Почему использование этого метода лучше, чем использование AbsoluteLayout? Только потому, что AbsoluteLayout устарела?
Натан

66

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

Следующий пример поместит ImageView размером 20x20 пикселей в позицию (100,200), используя 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:

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


2
Brilliant! Стоит 500! +1
Лиза Энн

16

Просто добавьте к ответу Энди Чжана, приведенному выше, если вы хотите, вы можете задать параметр для 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.


любил этот образец. Можете ли вы предложить мне, как я могу установить оси X, Y, когда у меня есть изображение в макете XML (я пытаюсь изменить размер изображения, и мне нужно установить изображение в некоторой позиции)
G_S

Боюсь, я не совсем понимаю, о чем ты спрашиваешь. Вы пытаетесь получить доступ к объекту LayoutParams, связанному с объектом, который был размещен с использованием макета XML? Я не уверен, как это сделано. Возможно, стоит задать новый вопрос, чтобы ответить на него, если вы не можете найти ответ в другом месте.
Мучительно

Пожалуйста, посмотрите на этот вопрос stackoverflow.com/questions/12028404/…
G_S

5

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

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

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

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


1

Проверьте скриншот

Поместите любую точку зрения по вашему желанию X & Y point

файл макета

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

Готово


0

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

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

myView.animate().translateX(pixelInScreen) 

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

кредиты к ответу bpr10


-1

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

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

-1

Мой код для 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;
                    }

            }

        }

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.