Встановіть абсолютне положення погляду


180

Чи можна встановити абсолютне положення перегляду в Android? (Я знаю, що є AbsoluteLayout, але це застаріло ...)

Наприклад, якщо у мене екран 240x320px, то як я можу додати значення ImageView20x20px таким чином, щоб його центр знаходився в положенні (100,100)?


3
також дивіться view.setTranslationX()абоview.offsetLeftAndRight()
Дрю Лесюер

Я щойно випустив бібліотеку, яка, можливо, тут зацікавила. github.com/ManuelPeinado/ImageLayout
Мануель

1
Це так складно, оскільки 99,9% часу абсолютного позиціонування є поганою ідеєю для андроїда. Якщо ви пишете додаток, який ТІЛЬКИ колись запускатиметься на одному фізичному пристрої, це може працювати, але це, як правило, не є надійним припущенням. Наприклад, не завантажуйте це в Google play. Він добре працює на iOS, оскільки є лише кілька апаратних пристроїв, і ви можете створити власну розкадровку для кожного з них.
edthethird

2
@edthethird, У своєму кросплатформенному додатку я отримую розмір екрана і базую все на цьому. Я просто перейшов на "застарілий" AbsoluteLayout, і він працює чудово.
Вільям Йокуш

досить справедливо, але це те, що відносна компонування або LinearLayout зробить для вас автоматично.
edthethird

Відповіді:


271

Ви можете використовувати RelativeLayout. Скажімо, ви хотіли зображення 30х40 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);

Більше прикладів:

Містить два зображення 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);

Поміщає один Imagex View 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);

1
Я спробую сьогодні ввечері, це дуже приємна ідея, не знаю, чому я не думав про це. Як я маю декілька ImageView, чи не було б краще використовувати FrameLayout?
Сефі

Насправді це, здається, працює, проте працює лише тоді, коли таким чином додати одну картину. якщо я спробую додати 2-й, перший просто зникає ...
Sephy

1
Два зображення знаходяться один на одного. Я додам трохи коду до свого рішення вище, щоб пояснити.
Енді Чжан

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

9
Чому використання цього методу може бути кращим, ніж використання AbsoluteLayout? Просто тому, що AbsoluteLayout застаріло?
Натан

66

Загалом, ви можете додати перегляд у певному положенні, використовуючи FrameLayout як контейнер, вказавши атрибути leftMargin та topMargin .

Наступний приклад розмістить зображення Image 20 View 20x20px у позиції (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) координати без відносного макета:

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


2
Блискуче! Варто 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;

Отже, якщо ви збережете змінну параметрів, ви можете змінити макет 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, замість жорсткого кодування цих пікселів / точок на дюйм у вашому коді Java.


1

Перевірте скріншот

Помістіть будь-який погляд на вашого бажання 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);
    }
}

Зроблено


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

            }

        }

Це було корисно для мене, оскільки мені потрібна властивість зору перекриватись один на одного за ознакою їх зовнішнього вигляду, наприклад, види перетинаються один над одним .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.