Bagaimana cara menampilkan Tampilan di RelativeLayout secara terprogram?

234

Saya mencoba mencapai hal-hal berikut secara terprogram (daripada secara deklaratif melalui XML):

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

Dengan kata lain, bagaimana cara membuat yang kedua TextViewmuncul di bawah yang pertama, tetapi saya ingin melakukannya dalam kode:

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

Memperbarui:

Terima kasih, TreeUK. Saya mengerti arah umum, tetapi masih tidak berhasil - "B" tumpang tindih "A". Apa yang saya lakukan salah?

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);
Dan
sumber
Dalam contoh kode Anda, Anda sebenarnya tidak menambahkan aturan RelativeLayout.BELOW, tv1.getId ();
Tristan Warner-Smith
48
Anda perlu memberikan id kepada pandangan anak Anda: tv1.setId (1); tv2.setId (2); Tampilan induk tidak secara otomatis menetapkan Id tampilan anak, dan nilai default untuk Id adalah NO_ID. Id tidak harus unik dalam tampilan hiearchy - jadi 1, 2, 3, dll semua adalah nilai yang baik untuk digunakan - dan Anda harus menggunakannya untuk anchoring relatif agar berfungsi di RelativeLayout.
sechastain

Jawaban:

196

Dari apa yang saya dapat kumpulkan, Anda harus menambahkan tampilan menggunakan LayoutParams.

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

Semua kredit untuk sechastain, untuk relatif memposisikan item Anda secara terprogram Anda harus menetapkan id untuk mereka.

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

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

Tristan Warner-Smith
sumber
1
dalam kasus saya selain mengatur id tampilan anak, menambahkan tampilan anak ke tampilan induk dan memanggil requestLayout () pada tampilan anak sebelum menetapkan aturan tampilan anak lain membuat hal-hal bekerja. Semoga ini bisa membantu seseorang
2cupsOfTech
Jika ada yang masih mengikuti ini: ketika saya memiliki koleksi pandangan saya menambahkan satu per satu dan saya tidak dapat memastikan bahwa salah satu pandangan bahwa item diatur menjadi belowtelah ditambahkan, bagaimana memastikan masih membuat benar? Dari pemahaman saya addViewmenyebabkan tata letak untuk dirender ulang, jadi jika saya melakukannya untuk item yang relatif belum ditambahkan, itu akan macet karena item dengan ID itu belum ada.
Megakoresh
1
set (id) harus digunakan dengan generateViewId () Ditambahkan di API level 17. Ini menghasilkan nilai yang cocok untuk digunakan di setId (int). Nilai ini tidak akan bertabrakan dengan nilai ID yang dihasilkan saat membangun oleh aapt untuk R.id. Contoh: tv [l_idx] .setId (View.generateViewId ());
AndrewBloom
Jawaban ini ditulis dengan sangat buruk. Apa alasan di balik penggunaan parameter RelationalLayout untuk tata letak Linear? Dan mengapa Anda menambahkan Tata Letak Linear ke Tampilan Induk?
pcodex
Hai @Prab, jawaban ini sekarang berumur 9 tahun. Jika Anda memiliki umpan balik positif tentang bagaimana jawabannya dapat ditingkatkan untuk kebutuhan hari ini, silakan tekan tombol edit dan sarankan 👍
Tristan Warner-Smith
60

Singkat cerita: Dengan tata letak relatif Anda memposisikan elemen di dalam tata letak.

  1. buat RelativeLayout.LayoutParams baru

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

    (apa pun ... isi induk atau bungkus konten, angka absolut jika Anda harus, atau referensi ke sumber daya XML)

  2. Tambahkan aturan: Aturan merujuk ke orang tua atau "saudara" lainnya dalam hierarki.

    lp.addRule(RelativeLayout.BELOW, someOtherView.getId())
    lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT)
  3. Cukup terapkan tata letak params: Cara yang paling 'sehat' untuk melakukannya adalah:

    parentLayout.addView(myView, lp)

Awas : Jangan mengubah tata letak dari tata letak panggilan balik. Sangat menggoda untuk melakukannya karena ini adalah saat tampilan mendapatkan ukuran sebenarnya. Namun, dalam hal itu, hasil yang tidak diharapkan diharapkan.

Meymann
sumber
Saya tidak tahu Anda bisa mengatur params ke Lihat dan menambahkan Tampilan ke orang tua itu Lihat semua dalam satu baris kode ( parentLayout.addView(myView, lp). Saya selalu melakukan itu dalam dua baris kode. Terima kasih!
Matt
Ini bekerja untuk saya dan banyak membantu, tetapi apakah ada cara untuk menyelaraskan anak di bawah sesuatu dan kemudian menetapkan margin di atas untuk anak itu? Atau bisakah saya mengatur margin di bawah untuk hal di bawah dan apakah akan menyesuaikan dengan benar?
Jacob Varner
Tentu ada. Anda dapat mengatur margin (sayangnya, API terprogram tidak senyaman XML) dengan setMargins (kiri, atas, kanan, bawah). Itu ada di LayoutParams. Perhatikan bahwa bantalan adalah properti tampilan, bukan tata letak params.
Meymann
29

Hanya menghabiskan 4 jam dengan masalah ini. Akhirnya menyadari bahwa Anda tidak boleh menggunakan nol sebagai id tampilan . Anda akan berpikir bahwa itu diizinkan sebagai NO_ID == -1, tetapi banyak hal cenderung menjadi berantakan jika Anda memberikannya pada pandangan Anda ...

fastfox
sumber
2
Saya melihat hal yang sama. Saya menggunakan API 7, dan melihat javadoc, saya melihat setID (int) menyatakan bahwa id harus berupa bilangan bulat positif. Itu adalah sesuatu yang harus ditegakkan dalam kode, tidak hanya dikomentari dalam dokumen. developer.android.com/reference/android/view/…
OYRM
@OYRM Android berantakan
SpaceMonkey
Anda sangat mungkin hanya menyelamatkan saya TON waktu. Terima kasih!
rjr-apps
9

Android 22 contoh runnable minimal

masukkan deskripsi gambar di sini

Sumber:

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

Bekerja dengan proyek default yang dihasilkan oleh android create project .... Repositori GitHub dengan kode build minimal .

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
1
Bisakah Anda memperluas contoh ini ke 3 TextView? Saya mencoba dan yang ketiga TextViewhilang.
Zizheng Wu
7

panggilan

tv1.setId(1) 

setelah

tv1.setText("A");
pengguna299870
sumber
Jika saya boleh bertanya, apa alasannya? Saya mengalami masalah tetapi saya menggunakan ImageView dan juga TextView jadi saya bertanya-tanya kapan harus memanggil .setId () pada ImageView.
Joshua G
FYI - Saya menelepon .setId () tepat sebelum saya menambahkan tampilan dan itu berhasil, tidak tahu mengapa .. lol
Joshua G
4

Mencoba:

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);
Phantômaxx
sumber
1
Bagus contoh yang paling berguna. Terima kasih.
Vyacheslav
2

Pendekatan ini dengan ViewGroup.MarginLayoutParams bekerja untuk saya:

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);
Gene Bo
sumber
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);
    }

}
Richa
sumber
0

Jika Anda benar-benar ingin tata letak secara manual, saya sarankan untuk tidak menggunakan tata letak standar sama sekali. Lakukan semuanya sendiri, ini contoh kotlin:

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

Ini mungkin memberi Anda gambaran bagaimana ini bisa berhasil

martyglaubitz
sumber