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.