Legen Sie die absolute Position einer Ansicht fest

180

Ist es möglich, die absolute Position einer Ansicht in Android festzulegen? (Ich weiß, dass es eine gibt AbsoluteLayout, aber sie ist veraltet ...)

Wenn ich beispielsweise einen Bildschirm mit 240 x 320 Pixel habe, wie kann ich dann einen Bildschirm mit einer Größe von 20 x 20 Pixel hinzufügen, ImageViewsodass sich seine Mitte an der Position (100.100) befindet?

Sephy
quelle
3
siehe auch view.setTranslationX()oderview.offsetLeftAndRight()
Drew LeSueur
Ich habe gerade eine Bibliothek veröffentlicht, die hier von Interesse gewesen sein könnte. github.com/ManuelPeinado/ImageLayout
Manuel
1
Dies ist so schwierig, weil 99,9% der Zeit absolute Positionierung eine schlechte Idee auf Android ist. Wenn Sie eine App schreiben, die NUR auf einem physischen Gerät ausgeführt wird, funktioniert dies möglicherweise, dies ist jedoch im Allgemeinen keine sichere Annahme. Laden Sie dies beispielsweise nicht auf Google Play hoch. Es funktioniert gut unter iOS, da es nur eine Handvoll Hardwaregeräte gibt und Sie für jedes ein benutzerdefiniertes Storyboard erstellen können.
3.
2
@edthethird, In meiner plattformübergreifenden App erhalte ich die Bildschirmgröße und stütze alles darauf. Ich habe gerade auf das "veraltete" AbsoluteLayout umgestellt und es funktioniert einwandfrei.
William Jockusch
Fair genug, aber genau das erledigt ein relatives Layout oder LinearLayout automatisch für Sie.
3.

Antworten:

270

Sie können RelativeLayout verwenden. Angenommen, Sie möchten eine 30x40-Bildansicht an der Position (50,60) in Ihrem Layout. Irgendwo in Ihrer Tätigkeit:

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

Mehr Beispiele:

Platziert zwei 30x40 ImageViews (eine gelbe, eine rote) bei (50,60) bzw. (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);

Platziert eine 30x40 gelbe ImageView bei (50,60) und eine weitere 30x40 rote ImageView <80,90> relativ zur gelben 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);
Andy Zhang
quelle
1
Ich werde es heute Abend versuchen, das ist eine ziemlich gute Idee, ich weiß nicht, warum ich nicht darüber nachgedacht habe. Wäre ImageViewes nicht besser, eine zu verwenden, da ich mehrere zu stellen habe FrameLayout?
Sephy
Dies scheint zwar zu funktionieren, funktioniert jedoch nur, wenn auf diese Weise ein Bild hinzugefügt wird. Wenn ich versuche, eine zweite hinzuzufügen, verschwindet die erste einfach ...
Sephy
1
Die beiden Bilder liegen direkt übereinander. Ich werde meiner obigen Lösung Code hinzufügen, um dies zu erklären.
Andy Zhang
2
Ja, das habe ich gestern auch gefunden, indem ich deine Lösung selbst ausgegraben habe. Ich probiere auch Sachen mit dem FrameLayout aus. Mein eigentliches Problem ist, dass ich 5 Bilder mit jeweils einer zufälligen (x, y) Position habe, daher kann ich RelativeLayout.RIGHT_OF oder ähnliches nicht verwenden. Das Seltsame ist, dass ich 3 Bilder bekommen kann, um sie richtig zu platzieren, aber 2 davon funktionieren nicht ... Ich verstehe nicht ... Ich werde meinen Beitrag heute Abend mit einigen Screenshots und etwas Code aktualisieren.
Sephy
9
Warum ist die Verwendung dieser Methode besser als die Verwendung von AbsoluteLayout? Nur weil AbsoluteLayout veraltet ist?
Nathan
66

Im Allgemeinen können Sie eine Ansicht an einer bestimmten Position mithilfe eines FrameLayout als Container hinzufügen, indem Sie die Attribute leftMargin und topMargin angeben .

Im folgenden Beispiel wird eine 20 x 20 Pixel große ImageView an Position (100.200) platziert, wobei ein FrameLayout als Vollbildcontainer verwendet wird:

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>

Aktivität / Fragment / Benutzerdefinierte Ansicht

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

Dies reicht aus, da Ränder als absolute (X, Y) Koordinaten ohne RelativeLayout verwendet werden können:

Geben Sie hier die Bildbeschreibung ein

bonnyz
quelle
2
Brillant! Die 500 wert! +1
Lisa Anne
16

Um Andy Zhangs Antwort oben zu ergänzen, können Sie rl.addView param geben und später Änderungen daran vornehmen, also:

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

Könnte genauso gut geschrieben werden als:

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

Wenn Sie also die Variable params beibehalten, können Sie das Layout von iv jederzeit ändern, nachdem Sie es zu rl hinzugefügt haben.

Exkrubulent
quelle
liebte diese Probe. Können Sie mir vorschlagen, wie ich die x-, y-Achse einstellen kann, wenn ich das Bild im XML-Layout habe
?
Ich fürchte, ich verstehe nicht ganz, was Sie fragen. Versuchen Sie, auf das LayoutParams-Objekt zuzugreifen, das einem Objekt zugeordnet ist, das mithilfe des XML-Layouts positioniert wurde? Ich bin mir nicht sicher, wie das gemacht wird. Es kann sich lohnen, eine neue Frage einzurichten, um diese zu beantworten, wenn Sie die Antwort an keiner anderen Stelle finden.
Exkrubulent
Bitte werfen Sie einen Blick auf diese Frage stackoverflow.com/questions/12028404/…
G_S
5

Eine sauberere und dynamischere Methode, ohne Pixelwerte im Code fest zu codieren.

Ich wollte einen Dialog (den ich im Handumdrehen aufblase) genau unter einer angeklickten Schaltfläche positionieren.

und löste es so:

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

Sie müssen jedoch sicherstellen, dass das übergeordnete Layout von myVieweine Instanz von ist RelativeLayout.

vollständigerer Code:

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

Auf diese Weise können Sie weiterhin erwarten, dass sich die Zielansicht an alle Layoutparameter anpasst, die mithilfe von Layout-XML-Dateien festgelegt wurden, anstatt diese Pixel / dps in Ihrem Java-Code fest zu codieren.

Hari Krishna Ganji
quelle
1

Screenshot überprüfen

Platzieren Sie eine beliebige Ansicht auf Ihren gewünschten X & Y- Punkt

Layoutdatei

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

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

Getan

Hiren Patel
quelle
0

Nur für den Fall, dass es jemandem hilft, können Sie diesen Animator ViewPropertyAnimator wie folgt ausprobieren

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

myView.animate().translateX(pixelInScreen) 

Hinweis: Dieses Pixel ist nicht relativ zur Ansicht. Dieses Pixel ist die Pixelposition auf dem Bildschirm.

Credits auf bpr10 Antwort

praveenb
quelle
-1

Versuchen Sie den folgenden Code, um die Ansicht an einem bestimmten Ort festzulegen: -

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

Mein Code für Xamarin , ich verwende FrameLayout für diesen Zweck und folgendes ist mein 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;
                    }

            }

        }

Es war nützlich für mich, weil ich die Eigenschaft der Ansicht brauchte, um sich aufgrund ihres Aussehens zu überlappen, z. B. werden die Ansichten übereinander gestapelt .

Technacron
quelle