Définir la position absolue d'une vue

180

Est-il possible de définir la position absolue d'une vue sous Android? (Je sais qu'il y a un AbsoluteLayout, mais c'est obsolète ...)

Par exemple, si j'ai un écran de 240x320px, comment pourrais-je ajouter un ImageViewqui fait 20x20px de telle sorte que son centre soit à la position (100,100)?

Sephy
la source
3
voir aussi view.setTranslationX()ouview.offsetLeftAndRight()
Drew LeSueur
Je viens de publier une bibliothèque qui pourrait avoir été intéressante ici. github.com/ManuelPeinado/ImageLayout
Manuel
1
C'est si difficile car 99,9% du temps, le positionnement absolu est une mauvaise idée sur Android. Si vous écrivez une application qui ne sera exécutée QUE sur un seul appareil physique, cela peut fonctionner, mais ce n'est généralement pas une hypothèse sûre à faire. Par exemple, ne téléchargez pas ceci sur Google Play. Cela fonctionne bien sur iOS car il n'y a qu'une poignée de périphériques matériels et vous pouvez créer un storyboard personnalisé pour chacun.
edthethird
2
@edthethird, Dans mon application multiplateforme, j'obtiens la taille de l'écran et je base tout sur cela. Je viens de passer à l'AbsoluteLayout "obsolète", et cela fonctionne très bien.
William Jockusch
assez juste, mais c'est ce qu'une mise en page relative ou une mise en page linéaire fera automatiquement pour vous.
edthethird

Réponses:

271

Vous pouvez utiliser RelativeLayout. Supposons que vous vouliez un ImageView 30x40 à la position (50,60) dans votre mise en page. Quelque part dans votre activité:

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

Plus d'exemples:

Place deux ImageViews 30x40 (une jaune, une rouge) à (50,60) et (80,90), respectivement:

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

Place un ImageView jaune 30x40 à (50,60) et un autre ImageView rouge 30x40 <80,90> par rapport à l' ImageView jaune:

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);
Andy Zhang
la source
1
Je vais essayer ce soir, c'est une très bonne idée, je ne sais pas pourquoi je n'y ai pas pensé. Comme j'en ai plusieurs ImageViewà mettre, ne serait-il pas préférable d'utiliser un FrameLayout?
Sephy
En effet, cela semble fonctionner, cependant, cela ne fonctionne que lorsque vous ajoutez une image de cette façon. si j'essaie d'en ajouter un 2ème, le premier disparaît juste ...
Sephy
1
Les deux images sont juste l'une sur l'autre. Je vais ajouter du code à ma solution ci-dessus pour expliquer.
Andy Zhang
2
Oui, en effet, j'ai trouvé ça hier aussi en creusant votre solution par moi-même. J'essaye aussi des trucs avec le FrameLayout. Mon problème réel est que j'ai 5 images avec chacune une position aléatoire (x, y), donc je ne peux pas utiliser RelativeLayout.RIGHT_OF ou quelque chose comme ça. La chose étrange est que je peux placer 3 images correctement mais 2 d'entre elles ne fonctionnent pas ... Je ne comprends pas ... Je vais mettre à jour mon message avec quelques captures d'écran ce soir et du code.
Sephy
9
Pourquoi utiliser cette méthode serait-il mieux que d'utiliser AbsoluteLayout? Juste parce qu'AbsoluteLayout est obsolète?
Nathan
66

En général, vous pouvez ajouter une vue à une position spécifique en utilisant un FrameLayout comme conteneur en spécifiant les attributs leftMargin et topMargin .

L'exemple suivant placera un ImageView 20x20px à la position (100,200) en utilisant un FrameLayout comme conteneur plein écran:

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>

Activité / Fragment / Vue personnalisée

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

Cela fera l'affaire car les marges peuvent être utilisées comme coordonnées absolues (X, Y) sans RelativeLayout:

entrez la description de l'image ici

Bonnyz
la source
2
Brillant! Vaut le 500! +1
Lisa Anne
16

Juste pour ajouter à la réponse d'Andy Zhang ci-dessus, si vous le souhaitez, vous pouvez donner un paramètre à rl.addView, puis y apporter des modifications plus tard, donc:

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

Pourrait également être écrit comme:

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

Donc, si vous conservez la variable params, vous pouvez changer la disposition de iv à tout moment après l'avoir ajoutée à rl.

Excrubulent
la source
J'ai adoré cet échantillon. Pouvez-vous me suggérer comment puis-je définir l'axe x, y lorsque j'ai l'image dans la mise en page XML. (J'essaie de redimensionner l'image et j'ai besoin de définir l'image à une certaine position)
G_S
J'ai peur de ne pas bien comprendre ce que vous demandez. Essayez-vous d'accéder à l'objet LayoutParams associé à un objet qui a été positionné à l'aide de la mise en page XML? Je ne sais pas comment cela se fait. Cela peut valoir la peine de créer une nouvelle question pour y répondre, si vous ne trouvez pas la réponse ailleurs.
Excrubulent
s'il vous plaît jeter un oeil à cette question stackoverflow.com/questions/12028404/…
G_S
5

Une manière plus propre et dynamique sans coder en dur les valeurs de pixel dans le code.

Je voulais positionner une boîte de dialogue (que je gonfle à la volée) exactement en dessous d'un bouton cliqué.

et l'a résolu de cette façon:

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

Cependant, vous devez vous assurer que la mise en page parent de myViewest une instance de RelativeLayout.

code plus complet:

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

De cette façon, vous pouvez toujours vous attendre à ce que la vue cible s'adapte à tous les paramètres de disposition définis à l'aide de fichiers XML de disposition, au lieu de coder en dur ces pixels / dps dans votre code Java.

Hari Krishna Ganji
la source
1

Vérifier la capture d'écran

Placez n'importe quelle vue sur votre désir X & Y point

fichier de mise en page

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

Terminé

Hiren Patel
la source
0

Juste au cas où cela pourrait aider quelqu'un, vous pouvez également essayer cet animateur ViewPropertyAnimator comme ci-dessous

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

myView.animate().translateX(pixelInScreen) 

Remarque: ce pixel n'est pas relatif à la vue. Ce pixel est la position du pixel sur l'écran.

crédits à la réponse bpr10

Praveenb
la source
-1

Essayez le code ci-dessous pour définir la vue sur un emplacement spécifique: -

            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);
duggu
la source
-1

Mon code pour Xamarin , j'utilise FrameLayout à cette fin et voici mon code:

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

            }

        }

Cela m'a été utile parce que j'avais besoin que la propriété de vue se chevauche en fonction de son apparence, par exemple, les vues sont empilées les unes sur les autres .

Technacron
la source