프로그래밍 방식으로 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.BELOW, tv1.getId ()의 규칙을 추가하지 않습니다.
Tristan Warner-Smith

48
자녀의 조회수에 ID를 제공해야합니다. tv1.setId (1); tv2.setId (2); 부모보기는 자식보기에 ID를 자동으로 할당하지 않으며 ID의 기본값은 NO_ID입니다. Id는 뷰 계층에서 고유하지 않아도됩니다. 따라서 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);

프로그램 적으로 아이템을 상대적으로 배치하려면 아이템에 아이디를 할당해야합니다.

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

그때 addRule(RelativeLayout.RIGHT_OF, tv1.getId());


1
필자의 경우 childview의 ID를 설정하는 것 외에도 childview를 parentview에 추가하고 childview에서 requestLayout ()을 호출하여 다른 childview의 규칙을 설정하면 작동합니다. 희망이 도움이 사람
2cupsOfTech

누군가가 여전히 이것을 따르는 경우 : 뷰 모음이있을 때 하나씩 추가하고 항목이 설정되도록 설정된 뷰 중 하나 below가 이미 추가되었는지 확신 할 수 없습니다. 바르게? 내 이해로 addView인해 레이아웃이 다시 렌더링되므로 상대 항목이 아직 추가되지 않은 항목에 대해 수행하면 해당 ID의 항목이 아직 없기 때문에 충돌이 발생합니다.
Megakoresh

1
set (id)는 generateViewId ()와 함께 사용해야합니다. API 레벨 17에 추가되었습니다. setId (int)에 사용하기에 적합한 값을 생성합니다. 이 값은 R.id에 적합하여 빌드시 생성 된 ID 값과 충돌하지 않습니다. 예 : tv [l_idx] .setId (View.generateViewId ());
AndrewBloom의

이 답변은 매우 나쁘게 작성되었습니다. 선형 레이아웃에 RelationalLayout 매개 변수를 사용하는 이유는 무엇입니까? 그리고 왜 부모 레이아웃에 선형 레이아웃을 추가합니까?
pcodex

@Prab,이 답변은 이제 9 살입니다. 당신이 대답은 오늘날의 요구에 맞게 개선 할 수있는 방법에 대한 몇 가지 긍정적 인 피드백이있는 경우, 👍 편집 버튼을 눌러 주시기 그것을 제안하십시오
트리스탄 워너 스미스

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)로 매개 변수를 View로 설정하고 부모 View에 View를 추가 할 수 있다는 것을 몰랐습니다 . 나는 항상 두 줄의 코드로 그렇게했습니다. 감사합니다!
Matt

이것은 나를 위해 일하고 많은 도움이되었지만 아이를 무언가 아래에 정렬 한 다음 그 아이의 마진을 설정하는 방법이 있습니까? 또는 아래에있는 것에 대해 아래 여백을 설정할 수 있고 올바르게 조정됩니까?
Jacob Varner

물론입니다. setMargins (왼쪽, 위쪽, 오른쪽, 아래쪽)로 여백을 설정할 수 있습니다 (불행히도 프로그래밍 방식 API는 XML만큼 편안하지 않습니다). LayoutParams에 있습니다. 패딩은 레이아웃 매개 변수가 아니라 뷰의 속성입니다.
Meymann

29

이 문제로 4 시간을 보냈습니다. 마지막 으로 view id로 0을 사용해서는 안된다는 것을 깨달았습니다 . 당신은 그것이 NO_ID == -1로 허용된다고 생각할 것입니다.


2
나도 똑같아 API 7을 사용하고 있으며 javadoc을 보면 setID (int)가 id가 양의 정수 여야 함을 나타냅니다. 단순히 문서에 주석을 달지 않고 코드에서 시행 해야하는 것입니다. developer.android.com/reference/android/view/…
OYRM

@OYRM 안드로이드는 엉망입니다
SpaceMonkey

당신은 아마 시간의 톤을 절약 할 수 있습니다. 감사!
rjr-apps

9

안드로이드 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");

물어볼 수있는 이유는 무엇입니까? 문제가 있지만 TextView뿐만 아니라 ImageView를 사용하고 있으므로 ImageView에서 .setId ()를 호출 할 때 궁금합니다.
Joshua G

참고-보기를 추가하기 직전에 .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
가장 유용한 예가 좋습니다. 감사.
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.