Pytanie Ustaw bezwzględną pozycję widoku


Czy możliwe jest ustawienie bezwzględnej pozycji widoku w systemie Android? (Wiem, że istnieje AbsoluteLayout, ale jest przestarzałe ...)

Na przykład, jeśli mam ekran 240x320px, jak mogę dodać ImageView który jest 20x20px taki, że jego środek jest na pozycji (100,100)?


163
2017-07-20 21:40


pochodzenie


Zobacz także view.setTranslationX() lub view.offsetLeftAndRight() - Drew LeSueur
Właśnie wydałem bibliotekę, która mogła być tutaj interesująca. github.com/ManuelPeinado/ImageLayout - Manuel
Jest to trudne, ponieważ 99,9% czasu pozycjonowania absolutnego jest złym pomysłem na Androida. Jeśli piszesz aplikację, która będzie TYLKO kiedykolwiek można uruchomić na jednym urządzeniu fizycznym, to może działać, ale na ogół nie jest to bezpieczne założenie. Na przykład nie przesyłaj tego do Google Play. Działa dobrze na iOS, ponieważ jest tylko kilka urządzeń sprzętowych i możesz stworzyć niestandardowy storyboard dla każdego z nich. - edthethird
@edthethird, W mojej aplikacji wieloplatformowej otrzymuję rozmiar ekranu i wszystko na tym bazuję. Właśnie przeszedłem do "przestarzałego" AbsoluteLayout i działa dobrze. - William Jockusch
Wystarczająco uczciwe, ale właśnie to Względny Układ lub LinearLayout zrobi dla ciebie automatycznie. - edthethird


Odpowiedzi:


Możesz użyć RelativeLayout. Załóżmy, że chcesz mieć obraz 30x40 na miejscu (50,60) w swoim układzie. Gdzieś w twojej działalności:

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

Więcej przykładów:

Umieszcza dwa obrazy 30x40 ImageViews (jeden żółty, jeden czerwony) w (50,60) i (80,90), odpowiednio:

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

Umieszcza jedno żółte zdjęcie 30x40 w widoku (50,60) i kolejne 30x40 czerwone Obrazek <80,90> względem żółty 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);

242
2017-07-20 22:58



Dziś wieczorem będę miał na to ochotę, to całkiem niezły pomysł, nie wiem, dlaczego nie myślałem o tym. Ponieważ mam kilka ImageView by umieścić, czy nie byłoby lepiej użyć a FrameLayout? - Sephy
Rzeczywiście wydaje się, że to działa, jednak działa tylko wtedy, gdy dodajemy jeden obraz w ten sposób. jeśli spróbuję dodać drugą, pierwsza znika po prostu ... - Sephy
Te dwa obrazy są tylko jeden na drugim. Dodam kod do powyższego rozwiązania, aby wyjaśnić. - Andy Zhang
Tak, znalazłem to również wczoraj, kopiąc twoje rozwiązanie na własną rękę. Próbuję też rzeczy z FrameLayout. Moim prawdziwym problemem jest to, że mam 5 obrazów z każdym przypadkowym (x, y) położeniem, więc nie mogę użyć RelativeLayout.RIGHT_OF lub czegoś podobnego. Dziwne jest to, że mogę poprawnie umieścić 3 obrazy, ale 2 z nich nie działają ... Nie rozumiem ... Zaktualizuję mój post z dzisiejszymi zrzutami ekranu i kodem. - Sephy
Dlaczego stosowanie tej metody byłoby lepsze niż używanie AbsoluteLayout? Tylko dlatego, że AbsoluteLayout jest przestarzałe? - Nathan


Ogólnie, możesz dodać widok w określonej pozycji używając FrameLayout jako kontener, określając atrybuty leftMargin i topMargin.

Poniższy przykład umieści obraz 20x20px na pozycji (100200) używając FrameLayout jako kontener pełnoekranowy:

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>

Aktywność / Fragment / Widok niestandardowy

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

To wystarczy, ponieważ marginesy mogą być używane jako bezwzględne (X, Y) bez RelativeLayout:

enter image description here


47
2018-01-07 17:15



Znakomity! Warto 500! +1 - Lisa Anne


Aby dodać do odpowiedzi Andy'ego Zhanga powyżej, jeśli chcesz, możesz podać parametr rl.addView, a następnie wprowadzić w nim zmiany później:

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

Można równie dobrze napisać jako:

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

Jeśli więc zachowasz zmienną params, możesz zmienić układ iv w dowolnym momencie po dodaniu go do rl.


15
2018-01-19 03:02



kochałem tę próbkę. Czy możesz zasugerować mi, jak mogę ustawić oś x, y, gdy mam obraz w układzie xml (próbuję zmienić rozmiar obrazu i muszę ustawić obraz w pewnym miejscu) - G_S
Obawiam się, że nie bardzo rozumiem, o co prosisz. Czy próbujesz uzyskać dostęp do obiektu LayoutParams powiązanego z obiektem, który został umieszczony za pomocą układu XML? Nie jestem pewien, jak to się robi. Może warto postawić nowe pytanie, aby odpowiedzieć na to pytanie, jeśli nie możesz znaleźć odpowiedzi w innym miejscu. - Excrubulent
proszę spojrzeć na to pytanie stackoverflow.com/questions/12028404/... - G_S


Bardziej przejrzysty i dynamiczny sposób bez kodowania dowolnych wartości pikseli w kodzie.

Chciałem ustawić okno dialogowe (które nadmuchuję w locie) dokładnie poniżej klikniętego przycisku.

i rozwiązał to w ten sposób:

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

Jednak musisz upewnić się, że układ macierzysty myView jest instancją RelativeLayout.

bardziej kompletny kod:

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

W ten sposób można się spodziewać, że widok docelowy dostosuje się do dowolnego zestawu parametrów układu za pomocą plików XML układu, zamiast na stałe kodować te piksele / dps w kodzie Java.


5
2017-07-31 14:08





Check screenshot

Umieść dowolny widok na swoje pragnienie X & Y punkt

plik układu

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

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

Gotowe


1
2018-06-02 04:25





Na wszelki wypadek może pomóc komuś, możesz także spróbować tego animatora ViewPropertyAnimator jak poniżej

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

myView.animate().translateX(pixelInScreen) 

Uwaga: Ten piksel nie jest względny w stosunku do widoku. Ten piksel to piksel   pozycja na ekranie.

kredyty do Odpowiedź bpr10


0
2017-07-26 10:25





Spróbuj poniżej kodu, aby ustawić widok w określonej lokalizacji: -

            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
2017-09-17 09:16





Mój kod dla Xamarin, ja używam FrameLayout w tym celu i poniżej jest mój kod:

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

            }

        }

Było to dla mnie użyteczne, ponieważ potrzebowałem właściwości widoku, aby nakładały się na siebie nawzajem na podstawie ich wyglądu, np. Widoki ułożone jeden nad drugim.


-1
2017-11-06 07:59