Imposta la posizione assoluta di una vista


180

È possibile impostare la posizione assoluta di una vista su Android? (So ​​che c'è un AbsoluteLayout, ma è deprecato ...)

Ad esempio, se ho uno schermo 240x320px, come potrei aggiungere uno ImageViewche è 20x20px in modo tale che il suo centro sia nella posizione (100,100)?


3
vedi anche view.setTranslationX()oview.offsetLeftAndRight()
— Drew LeSueur il

Ho appena pubblicato una biblioteca che potrebbe essere stata di interesse qui. github.com/ManuelPeinado/ImageLayout
— Manuel,

1
Questo è così difficile perché il 99,9% delle volte il posizionamento assoluto è una cattiva idea su Android. Se stai scrivendo un'app che verrà eseguita SOLO su un solo dispositivo fisico, potrebbe funzionare, ma in genere non è un presupposto sicuro da fare. Ad esempio, non caricare questo su Google Play. Funziona bene su iOS perché ci sono solo una manciata di dispositivi hardware e puoi creare uno storyboard personalizzato per ognuno.
— edthirdird

2
@edthethird, Nella mia app multipiattaforma, ottengo le dimensioni dello schermo e baso tutto su quello. Sono appena passato al "obsoleto" AbsoluteLayout, e funziona benissimo.
— William Jockusch,

abbastanza giusto, ma questo è ciò che un layout relativo o un layout lineare farà automaticamente per te.
— terzo

Risposte:


271

È possibile utilizzare RelativeLayout. Diciamo che volevi un ImageView 30x40 in posizione (50,60) all'interno del layout. Da qualche parte nella tua attività:

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

Altri esempi:

Posiziona due visualizzazioni Image 30x40 (una gialla, una rossa) rispettivamente a (50,60) e (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);

Posiziona un ImageView giallo 30x40 in (50,60) e un altro ImageView rosso 30x40 <80,90> rispetto al ImageView giallo:

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
Ci proverò stasera, è una bella idea, non so perché non ci abbia pensato. Come ho molti ImageViewda mettere, non sarebbe meglio usare un FrameLayout?
— Sephy,

In effetti questo sembra funzionare, tuttavia, funziona solo quando aggiungi un'immagine in questo modo. se provo ad aggiungerne un secondo, il primo svanisce ...
— Sephy,

1
Le due immagini sono una sopra l'altra. Aggiungerò del codice alla mia soluzione sopra per spiegare.
— Andy Zhang,

2
Sì, l'ho scoperto anche ieri scavando la tua soluzione da solo. Provo anche cose con FrameLayout. Il mio vero problema è che ho 5 immagini con ciascuna una posizione casuale (x, y), quindi non posso usare RelativeLayout.RIGHT_OF o qualcosa del genere. La cosa strana è che posso ottenere 3 immagini per essere posizionate correttamente, ma 2 di loro non funzionano ... Non capisco ... Aggiornerò il mio post con alcuni screenshot stasera e un po 'di codice.
— Sephy,

9
Perché usare questo metodo sarebbe meglio che usare AbsoluteLayout? Solo perché AbsoluteLayout è obsoleto?
— Nathan,

66

In generale, è possibile aggiungere una vista in una posizione specifica usando FrameLayout come contenitore specificando gli attributi leftMargin e topMargin .

L'esempio seguente posizionerà un ImageView 20x20px in posizione (100.200) usando un FrameLayout come contenitore a schermo intero:

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>

Attività / Frammento / Vista personalizzata

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

Questo farà il trucco perché i margini possono essere usati come coordinate assolute (X, Y) senza un RelativeLayout:

inserisci qui la descrizione dell'immagine


2
Brillante! Vale la 500! +1
— Lisa Anne,

16

Solo per aggiungere alla risposta di Andy Zhang sopra, se vuoi, puoi dare param a rl.addView, quindi apportare modifiche in seguito, quindi:

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

Potrebbe anche essere scritto come:

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

Quindi, se si mantiene la variabile params, è possibile modificare il layout di iv in qualsiasi momento dopo averlo aggiunto a rl.


mi è piaciuto molto questo campione. Puoi suggerirmi come posso impostare l'asse x, y quando sto avendo l'immagine nel layout xml. (Sto cercando di ridimensionare l'immagine e ho bisogno di impostare l'immagine in una certa posizione)
— G_S

Temo di non capire bene cosa stai chiedendo. Stai tentando di accedere all'oggetto LayoutParams associato a un oggetto che è stato posizionato utilizzando il layout XML? Non sono sicuro di come sia stato fatto. Potrebbe essere utile impostare una nuova domanda per ottenere una risposta, se non riesci a trovare la risposta altrove.
— Excrubulent,

si prega di dare un'occhiata a questa domanda stackoverflow.com/questions/12028404/...
— G_S

5

Un modo più pulito e dinamico senza codificare i valori dei pixel nel codice.

Volevo posizionare una finestra di dialogo (che gonfio al volo) esattamente sotto un pulsante cliccato.

e risolto in questo modo:

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

Tuttavia, è necessario assicurarsi che il layout principale di myViewsia un'istanza di RelativeLayout.

codice più completo:

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

In questo modo puoi comunque aspettarti che la vista di destinazione si adegui a tutti i parametri di layout impostati utilizzando i file XML di layout, anziché codificare i pixel / dps nel tuo codice Java.


1

Controlla lo screenshot

Posiziona qualsiasi vista sul punto X e Y desiderato

file di layout

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

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

Fatto


0

Nel caso in cui possa aiutare qualcuno, puoi anche provare questo animatore ViewPropertyAnimator come di seguito

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

myView.animate().translateX(pixelInScreen) 

Nota: questo pixel non è relativo alla vista. Questo pixel è la posizione del pixel sullo schermo.

crediti a risposta bpr10


-1

Prova sotto il codice per impostare la visualizzazione su una posizione specifica: -

            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

Il mio codice per Xamarin , sto usando FrameLayout per questo scopo e di seguito è il mio codice:

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

            }

        }

Mi è stato utile perché avevo bisogno della proprietà della vista per sovrapporsi in base al loro aspetto, ad esempio le viste si sovrapponevano l'una sopra l'altra .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.