วิธีการจัดโครงสร้าง Views ใน RelativeLayout โดยทางโปรแกรม


234

ฉันพยายามที่จะบรรลุโปรแกรมต่อไปนี้ (แทนที่จะประกาศผ่าน XML):

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

ในคำอื่น ๆ ฉันจะทำให้ที่สองTextViewปรากฏอยู่ด้านล่างหนึ่งคนแรก แต่ฉันต้องการที่จะทำในรหัส:

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

ปรับปรุง:

ขอบคุณ TreeUK ฉันเข้าใจทิศทางทั่วไป แต่ก็ยังใช้งานไม่ได้ - "B" ทับ "A" ผมทำอะไรผิดหรือเปล่า?

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

ในตัวอย่างโค้ดของคุณคุณไม่ได้เพิ่มกฎของ RelativeLayout จริงๆเบลโล, tv1.getId ();
Tristan Warner-Smith

48
คุณต้องระบุ ID ให้กับมุมมองลูกของคุณ: tv1.setId (1); tv2.setId (2); มุมมองพาเรนต์ไม่ได้กำหนด ID มุมมองเด็กโดยอัตโนมัติและค่าเริ่มต้นสำหรับรหัสคือ NO_ID รหัสไม่จำเป็นต้องไม่ซ้ำกันในมุมมอง hiearchy ดังนั้น 1, 2, 3 และอื่น ๆ ล้วนเป็นค่าที่ดีที่จะใช้ - และคุณต้องใช้มันเพื่อการยึดสัมพัทธ์เพื่อทำงานใน RelativeLayout
sechastain

คำตอบ:


196

จากสิ่งที่ฉันสามารถรวมเข้าด้วยกันคุณต้องเพิ่มมุมมองโดยใช้ 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);

เครดิตทั้งหมดเพื่อ sechastain เพื่อวางตำแหน่งรายการของคุณโดยทางโปรแกรมคุณต้องกำหนดรหัสให้กับพวกเขา

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

แล้วก็ addRule(RelativeLayout.RIGHT_OF, tv1.getId());


1
ในกรณีของฉันนอกเหนือจากการตั้งค่ารหัสของ childview ให้เพิ่ม childview ลงใน parentview และการร้องขอ requestLayout () บน childview ก่อนกำหนดกฎของ childview อื่น ๆ ที่ทำให้สิ่งต่าง ๆ ทำงานได้ หวังว่านี่จะช่วยใครซักคน
2cupsOfTech

ในกรณีที่ทุกคนยังคงติดตามสิ่งนี้: เมื่อฉันมีคอลเลกชันของมุมมองฉันกำลังเพิ่มทีละคนและฉันไม่สามารถมั่นใจได้ว่าหนึ่งในมุมมองที่รายการถูกตั้งค่าให้belowมีการเพิ่มแล้ววิธีการให้แน่ใจว่ามันยังคงทำให้ ถูกต้องหรือไม่ จากความเข้าใจของฉันaddViewทำให้รูปแบบการแสดงผลซ้ำดังนั้นถ้าฉันทำเพื่อรายการที่ยังไม่ได้เพิ่มญาติก็จะเกิดความผิดพลาดเนื่องจากรายการที่มี ID นั้นยังไม่มี
Megakoresh

1
set (id) ควรใช้กับ generateViewId () เพิ่มใน API ระดับ 17 มันสร้างค่าที่เหมาะสมสำหรับใช้ใน setId (int) ค่านี้จะไม่ชนกับค่า ID ที่สร้างในเวลาบิลด์โดย aapt สำหรับ R.id ตัวอย่าง: tv [l_idx] .setId (View.generateViewId ());
AndrewBloom

คำตอบนี้เขียนไม่ดีมาก เหตุผลเบื้องหลังการใช้พารามิเตอร์ RelationalLayout สำหรับเค้าโครงแบบเส้นตรงคืออะไร และทำไมคุณจึงเพิ่ม Linear Layout ลงในมุมมองพาเรนต์
pcodex

เฮ้ @Prab คำตอบนี้อายุ 9 ปีแล้ว หากคุณมีข้อเสนอแนะในเชิงบวกเกี่ยวกับวิธีการปรับปรุงคำตอบสำหรับความต้องการของวันนี้โปรดกดปุ่มแก้ไขและแนะนำมัน👍
Tristan Warner-Smith

60

ตัดสั้นเรื่องยาว: ด้วยเค้าโครงที่สัมพันธ์กันคุณกำหนดตำแหน่งองค์ประกอบภายในเค้าโครง

  1. สร้าง RelativeLayout ใหม่ LayoutParams ใหม่

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

    (อะไรก็ตาม ... เติมเนื้อหาหลักหรือเนื้อหาที่มีการครอบตัดตัวเลขที่แน่นอนหากคุณต้องการหรืออ้างอิงถึงทรัพยากร XML)

  2. เพิ่มกฎ: กฎอ้างอิงถึงผู้ปกครองหรือ "พี่น้อง" คนอื่น ๆ ในลำดับชั้น

    lp.addRule(RelativeLayout.BELOW, someOtherView.getId())
    lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT)
  3. เพียงใช้เค้าโครงเค้าโครง: วิธีที่ดีที่สุดในการทำเช่นนี้คือ:

    parentLayout.addView(myView, lp)

ระวัง : อย่าเปลี่ยนเค้าโครงจากการเรียกกลับเค้าโครง การทำเช่นนี้น่าดึงดูดเพราะเมื่อมุมมองมีขนาดตามจริง อย่างไรก็ตามในกรณีนั้นคาดว่าจะได้ผลลัพธ์ที่ไม่คาดคิด


ฉันไม่รู้ว่าคุณสามารถตั้งค่าพารามิเตอร์เป็นมุมมองและเพิ่มมุมมองไปที่มันเป็นผู้ปกครองดูทั้งหมดในหนึ่งบรรทัดของรหัส ( parentLayout.addView(myView, lp) ฉันทำอย่างนั้นกับโค้ดสองบรรทัดเสมอ ขอบคุณ!
Matt

สิ่งนี้ได้ผลสำหรับฉันและช่วยได้มาก แต่มีวิธีจัดแนวเด็กด้านล่างหรือเปล่าแล้วตั้งระยะขอบด้านบนให้กับเด็กคนนั้น หรือฉันสามารถตั้งค่าระยะขอบด้านล่างสำหรับสิ่งที่อยู่ด้านล่างและจะปรับได้อย่างถูกต้องหรือไม่?
Jacob Varner

แน่นอนว่ามี คุณสามารถตั้งค่าระยะขอบ (น่าเสียดายที่ API เชิงโปรแกรมไม่สะดวกเท่ากับ XML) ด้วย setMargins (ซ้าย, บน, ขวา, ล่าง) มันอยู่ใน LayoutParams โปรดทราบว่าการขยายเป็นคุณสมบัติของมุมมองไม่ใช่การวางโครงร่าง
Meymann

29

เพิ่งใช้เวลา 4 ชั่วโมงกับปัญหานี้ ตระหนักในที่สุดว่าคุณต้องไม่ใช้เป็นศูนย์ View ID คุณจะคิดว่ามันได้รับอนุญาตเป็น NO_ID == -1 แต่สิ่งต่าง ๆ มักจะยุ่งเหยิงถ้าคุณให้มันในมุมมองของคุณ ...


2
ฉันเห็นเหมือนกัน ฉันใช้ API 7 และดู javadoc ฉันเห็นว่า setID (int) ระบุว่า id ควรเป็นจำนวนเต็มบวก มันเป็นสิ่งที่ควรมีการบังคับใช้ในรหัสไม่ใช่เพียงแค่แสดงความคิดเห็นในเอกสาร developer.android.com/reference/android/view/…
OYRM

@OYRM Android เป็นระเบียบ
SpaceMonkey

คุณอาจช่วยฉันได้เพียงหนึ่งตัน ขอบคุณ!
rjr-apps

9

ตัวอย่างที่รันได้น้อยที่สุดของ Android 22

ป้อนคำอธิบายรูปภาพที่นี่

ที่มา:

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

android create project ...ทำงานร่วมกับโครงการเริ่มต้นที่สร้างขึ้นโดย พื้นที่เก็บข้อมูล GitHub กับการสร้างรหัสที่น้อยที่สุด


1
คุณขยายตัวอย่างนี้เป็น 3 ได้TextViewไหม ฉันพยายามแล้วครั้งที่สามTextViewก็หายไป
Zizheng Wu

7

โทร

tv1.setId(1) 

หลังจาก

tv1.setText("A");

ถ้าฉันจะถามเหตุผลคืออะไร? ฉันกำลังมีปัญหา แต่ฉันใช้ ImageView เช่นเดียวกับ TextView ฉันจึงสงสัยว่าเมื่อใดที่จะเรียก. setId () บน ImageView
Joshua G

FYI - ฉันเรียกว่า. setId () ก่อนที่ฉันจะเพิ่มมุมมองและใช้งานได้ไม่ทราบว่าทำไม .. lol
Joshua G

4

ลอง:

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
Nice ตัวอย่างที่มีประโยชน์ที่สุด ขอบคุณ
Vyacheslav

2

วิธีการนี้กับ ViewGroup.MarginLayoutParams ใช้ได้สำหรับฉัน:

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

หากคุณต้องการจัดวางด้วยตนเองจริง ๆ ฉันขอแนะนำไม่ให้ใช้เค้าโครงมาตรฐานเลย ทำทุกอย่างด้วยตัวเองนี่คือตัวอย่างของ 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)
    }
}

นี่อาจทำให้คุณมีความคิดว่ามันใช้งานได้อย่างไร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.