如何以编程方式在RelativeLayout中布局视图?

我试图实现以下编程方式(而不是通过XML声明):

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

换句话说,我如何使第二个TextView出现在第一个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);
200710 次浏览

根据我所能够拼凑的内容,您必须使用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,以编程方式相对定位您的项目,您必须为它们分配id。

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

然后addRule(RelativeLayout.RIGHT_OF, tv1.getId());

调用

tv1.setId(1)

tv1.setText("A");
长话短说: 使用相对布局,你可以在布局中放置元素
  1. 创建新的RelativeLayout。LayoutParams

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

    (不管…填充父内容或换行内容,绝对数字(如果必须,或引用XML资源)

  2. <李> < p >添加规则: 规则指的是父级或层次结构中的其他“兄弟”
    lp.addRule(RelativeLayout.BELOW, someOtherView.getId())
    lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT)
    
  3. Just apply the layout params: The most 'healthy' way to do that is:

    parentLayout.addView(myView, lp)
    

Watch out: Don't change layout from the layout callbacks. It is tempting to do so because this is when views get their actual sizes. However, in that case, unexpected results are expected.

我花了4个小时来解决这个问题。终于意识到你必须不使用零作为视图id。你可能认为NO_ID == -1是允许的,但是如果你把它给你的视图,事情就会变得混乱…

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

试一试:

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

Android 22最小可运行的例子

enter image description here

来源:

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存储库与最小的构建代码

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


}

如果你真的想手动布局,我建议不要使用标准布局。这是一个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)
}
}

这可能会让你知道它是如何工作的