RelativeLayout'taki Görünümleri programlı olarak nasıl düzenleyebilirim?


234

Aşağıdaki programlı (XML üzerinden bildirici yerine) elde etmeye çalışıyorum:

<RelativeLayout...>
   <TextView ...
      android:id="@+id/label1" />
   <TextView ...
      android:id="@+id/label2"
      android:layout_below: "@id/label1" />
</RelativeLayout>

Başka bir deyişle, nasıl TextViewbirincinin altında ikinci görünmesini nasıl yapabilirim , ama kodda yapmak istiyorum:

RelativeLayout layout = new RelativeLayout(this);
TextView label1 = new TextView(this);
TextView label2 = new TextView(this);
...
layout.addView(label1);
layout.addView(label2);
setContentView(layout);

Güncelleme:

Teşekkürler, TreeUK. Genel yönü anlıyorum, ama hala çalışmıyor - "B" "A" ile çakışıyor. Neyi yanlış yapıyorum?

RelativeLayout layout = new RelativeLayout(this);
TextView tv1 = new TextView(this);
tv1.setText("A");

TextView tv2 = new TextView(this);
tv2.setText("B");
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
        RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.FILL_PARENT);
lp.addRule(RelativeLayout.RIGHT_OF, tv1.getId());

layout.addView(tv1);        
layout.addView(tv2, lp);

Kod örneğinizde, aslında RelativeLayout.BELOW, tv1.getId ();
Tristan Warner-Smith

48
çocuğunuzun görünümlerine kimlik sağlamanız gerekir: tv1.setId (1); tv2.setId (2); Üst görünümler otomatik olarak alt görünümlere bir Kimlik atamaz ve bir Kimlik için varsayılan değer NO_ID'dir. Kimliklerin bir görünüm aramasında benzersiz olması gerekmez; bu nedenle, 1, 2, 3 vb. Tümü kullanılacak ince değerlerdir ve bunları göreli sabitlemenin RelativeLayout'ta çalışması için kullanmanız gerekir.
sechastain

Yanıtlar:


196

Bir araya getirebildiğim kadarıyla, LayoutParams'ı kullanarak görünümü eklemelisiniz.

LinearLayout linearLayout = new LinearLayout(this);

RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);

parentView.addView(linearLayout, relativeParams);

Tüm kredileri elde etmek, öğelerinizi programlı olarak göreceli olarak konumlandırmak için bunlara kimlik atamanız gerekir.

TextView tv1 = new TextView(this);
tv1.setId(1);
TextView tv2 = new TextView(this);
tv2.setId(2);

Sonra addRule(RelativeLayout.RIGHT_OF, tv1.getId());


1
benim durumumda, bir alt görünümün kimliklerini ayarlamak, üst görünümüne alt görünüm eklemek ve alt görünümün diğer alt görünüm kurallarını ayarlamadan önce alt görünümde requestLayout () öğesini çağırmak dışında işler işe yaradı. Umut etmek bu kimse yardımcı olur
2cupsOfTech

Herkes hala bunu izliyorsa: Ben bir koleksiyon bir koleksiyon var tek tek ekliyorum ve bir öğe olarak ayarlanmış görünümlerden biri belowzaten eklenmiş olduğundan emin olamaz , nasıl hala render emin olmak için doğru şekilde? Anladığım kadarıyla addView, mizanpajın yeniden oluşturulmasına neden oluyor, bu yüzden henüz akrabası olmayan bir öğe için yaparsam, bu kimliğe sahip öğe henüz mevcut olmadığından çökecektir.
Megakoresh

1
set (id), API düzeyi 17'de eklenen createViewId () ile kullanılmalıdır. setId (int) içinde kullanıma uygun bir değer üretir. Bu değer, rid için aapt tarafından derleme sırasında oluşturulan kimlik değerleriyle çarpışmaz. Örnek: tv [l_idx] .setId (View.generateViewId ());
AndrewBloom

Bu cevap çok kötü yazılmış. Doğrusal bir düzen için RelationalLayout parametrelerini kullanmanın ardındaki mantık nedir? Ve bir Ana Görünüme neden Doğrusal Düzeni ekliyorsunuz?
pcodex

Hey @Prab, bu cevap şimdi 9 yaşında. Cevabın bugünün ihtiyaçları için nasıl geliştirilebileceğine dair olumlu geribildiriminiz varsa, lütfen düzenleme düğmesine basmaktan çekinmeyin ve önerin suggest
Tristan Warner-Smith

60

Uzun hikayeyi kısa kesin: Göreli düzen ile öğeleri düzenin içine yerleştirirsiniz.

  1. yeni bir RelativeLayout.LayoutParams oluşturun

    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(...)

    (her neyse ... içeriği doldurun veya içeriği sarın, gerekiyorsa mutlak sayılar veya bir XML kaynağına başvurma)

  2. Kural ekleme: Kurallar, ana öğeye veya hiyerarşideki diğer "kardeşlere" karşılık gelir.

    lp.addRule(RelativeLayout.BELOW, someOtherView.getId())
    lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT)
    
  3. Sadece düzen parametrelerini uygulayın: Bunu yapmanın en 'sağlıklı' yolu:

    parentLayout.addView(myView, lp)

Dikkat : Düzeni geri aramalardan düzeni değiştirmeyin. Bunu yapmak cazip gelebilir, çünkü bu görünümlerin gerçek boyutlarını almasıdır. Ancak bu durumda beklenmedik sonuçlar beklenir.


Ben bir Görünüm için params ayarlamak ve onun üst bir görünüm eklemek hiçbir fikrim yoktu Tüm kod satırında görüntüle ( parentLayout.addView(myView, lp). Bunu her zaman iki kod satırında yaptım. Teşekkür ederim!
Matt

Bu benim için işe yaradı ve çok yardımcı oldu, ancak çocuğu bir şeyin altına hizalamanın ve sonra bu çocuğun marjını yukarıda ayarlamanın bir yolu var mı? Ya da aşağıda olduğu için kenar boşluğunu ayarlayabilir miyim ve doğru ayarlanacak mı?
Jacob Varner

Elbette var. SetMargins (sol, üst, sağ, alt) ile kenar boşluklarını ayarlayabilirsiniz (maalesef, programlı API XML kadar rahat değildir). LayoutParams içinde. Doldurmanın mizanpaj parametrelerini değil, görünümün bir özelliği olduğunu unutmayın.
Meymann

29

Sadece bu sorun ile 4 saat geçirdim. Sonunda sıfır olarak view id olarak kullanılmamanız gerektiğini fark ettik . NO_ID == -1 olarak izin verildiğini düşünürsünüz, ancak görünümünüze verirseniz işler haywire'a gitme eğilimindedir ...


2
Ben de aynısını görüyorum. API 7 kullanıyorum ve javadoc görüntülüyor setID (int) id pozitif bir tamsayı gerektiğini belirtiyor görüyorum. Bu sadece dokümanlar hakkında yorum yapmakla kalmayıp, kodda uygulanması gereken bir şeydir. developer.android.com/reference/android/view/…
OYRM

@OYRM Android bir karmaşa
SpaceMonkey

Muhtemelen bana bir ton zaman kazandın. Teşekkürler!
rjr-apps

9

Android 22 minimum çalıştırılabilir örnek

resim açıklamasını buraya girin

Kaynak:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class Main extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final RelativeLayout relativeLayout = new RelativeLayout(this);

        final TextView tv1;
        tv1 = new TextView(this);
        tv1.setText("tv1");
        // Setting an ID is mandatory.
        tv1.setId(View.generateViewId());
        relativeLayout.addView(tv1);

        // tv2.
        final TextView tv2;
        tv2 = new TextView(this);
        tv2.setText("tv2");
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.FILL_PARENT);
        lp.addRule(RelativeLayout.BELOW, tv1.getId());
        relativeLayout.addView(tv2, lp);

        // tv3.
        final TextView tv3;
        tv3 = new TextView(this);
        tv3.setText("tv3");
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        );
        lp2.addRule(RelativeLayout.BELOW, tv2.getId());
        relativeLayout.addView(tv3, lp2);

        this.setContentView(relativeLayout);
    }
}

Tarafından oluşturulan varsayılan proje ile çalışır android create project .... Minimum yapı koduna sahip GitHub deposu .


1
Bu örneği 3'e genişletebilir misiniz TextView? Denedim ve üçüncü TextVieweksik.
Zizheng Wu

7

aramak

tv1.setId(1) 

sonra

tv1.setText("A");

Eğer sorabilirsem, nedeni nedir? Bir sorun yaşıyorum ama ImageView yanı sıra ne zaman ImageView .setId () çağırmak merak ediyorum TextView kullanıyorum.
Joshua G

FYI - Görünümü eklemeden hemen önce .setId () çağırdım ve işe yaradı, neden hiçbir fikrim yok .. lol
Joshua G

4

Deneyin:

EditText edt = (EditText) findViewById(R.id.YourEditText);
RelativeLayout.LayoutParams lp =
    new RelativeLayout.LayoutParams
    (
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
    );
lp.setMargins(25, 0, 0, 0); // move 25 px to right (increase left margin)
edt.setLayoutParams(lp); // lp.setMargins(left, top, right, bottom);

1
Güzel en faydalı örnek. Teşekkürler.
Vyacheslav

2

ViewGroup.MarginLayoutParams ile bu yaklaşım benim için çalıştı:

RelativeLayout myLayout = (RelativeLayout) findViewById(R.id.my_layout);

TextView someTextView = ...

int leftMargin = Util.getXPos();
int topMargin = Util.getYPos();

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
    new ViewGroup.MarginLayoutParams(
        RelativeLayout.LayoutParams.WRAP_CONTENT,
        RelativeLayout.LayoutParams.WRAP_CONTENT));

lp.setMargins(leftMargin, topMargin, 0, 0);

myLayout.addView(someTextView, lp);

1
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);

        final RelativeLayout relativeLayout = new RelativeLayout(this);
        final TextView tv1 = new TextView(this);
        tv1.setText("tv1 is here");
        // Setting an ID is mandatory.
        tv1.setId(View.generateViewId());
        relativeLayout.addView(tv1);


        final TextView tv2 = new TextView(this);
        tv2.setText("tv2 is here");

        // We are defining layout params for tv2 which will be added to its  parent relativelayout.
        // The type of the LayoutParams depends on the parent type.
        RelativeLayout.LayoutParams tv2LayoutParams = new  RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.WRAP_CONTENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT);

        //Also, we want tv2 to appear below tv1, so we are adding rule to tv2LayoutParams.
        tv2LayoutParams.addRule(RelativeLayout.BELOW, tv1.getId());

        //Now, adding the child view tv2 to relativelayout, and setting tv2LayoutParams to be set on view tv2.
        relativeLayout.addView(tv2);
        tv2.setLayoutParams(tv2LayoutParams);
        //Or we can combined the above two steps in one line of code
        //relativeLayout.addView(tv2, tv2LayoutParams);

        this.setContentView(relativeLayout);
    }

}

0

Gerçekten elle düzenlemek istiyorsanız, standart bir düzen kullanmamanızı öneririm. Her şeyi kendiniz yapın, burada bir kotlin örneği:

class ProgrammaticalLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ViewGroup(context, attrs, defStyleAttr) { 
    private val firstTextView = TextView(context).apply {
        test = "First Text"
    }

    private val secondTextView = TextView(context).apply {
        text = "Second Text"
    }

    init {
        addView(firstTextView)
        addView(secondTextView)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        // center the views verticaly and horizontaly
        val firstTextLeft = (measuredWidth - firstTextView.measuredWidth) / 2
        val firstTextTop = (measuredHeight - (firstTextView.measuredHeight + secondTextView.measuredHeight)) / 2
        firstTextView.layout(firstTextLeft,firstTextTop, firstTextLeft + firstTextView.measuredWidth,firstTextTop + firstTextView.measuredHeight)

        val secondTextLeft = (measuredWidth - secondTextView.measuredWidth) / 2
        val secondTextTop = firstTextView.bottom
        secondTextView.layout(secondTextLeft,secondTextTop, secondTextLeft + secondTextView.measuredWidth,secondTextTop + secondTextView.measuredHeight)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 
        // just assume we`re getting measured exactly by the parent
        val measuredWidth = MeasureSpec.getSize(widthMeasureSpec)
        val measuredHeight = MeasureSpec.getSize(heightMeasureSpec)

        firstTextView.measures(MeasureSpec.makeMeasureSpec(meeasuredWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
        secondTextView.measures(MeasureSpec.makeMeasureSpec(meeasuredWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))

        setMeasuredDimension(measuredWidth, measuredHeight)
    }
}

Bu size bunun nasıl çalışabileceği hakkında bir fikir verebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.