简体   繁体   English

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

[英]How to lay out Views in RelativeLayout programmatically?

I'm trying to achieve the following programmatically (rather than declaratively via XML): 我正在尝试以编程方式(而不是通过XML声明性地)实现以下目标:

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

In other words, how do I make the second TextView appear below the first one, but I want to do it in code: 换句话说,如何使第二个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);

Update: 更新:

Thanks, TreeUK. 谢谢,TreeUK。 I understand the general direction, but it still doesn't work - "B" overlaps "A". 我了解总体方向,但仍然无法正常工作-“ B”与“ A”重叠。 What am I doing wrong? 我究竟做错了什么?

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

From what I've been able to piece together, you have to add the view using LayoutParams. 根据我的拼凑,您必须使用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);

All credit to sechastain, to relatively position your items programmatically you have to assign ids to them. 所有值得信赖的东西,要以编程方式相对放置您的物品,您必须为其分配ID。

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

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

Cut the long story short: With relative layout you position elements inside the layout. 简而言之:使用相对布局可以将元素放置在布局内。

  1. create a new RelativeLayout.LayoutParams 创建一个新的RelativeLayout.LayoutParams

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

    (whatever... fill parent or wrap content, absolute numbers if you must, or reference to an XML resource) (无论如何...填写父项或换行内容,如果必须,请输入绝对数字,或引用XML资源)

  2. Add rules: Rules refer to the parent or to other "brothers" in the hierarchy. 添加规则:规则引用层次结构中的父级或其他“兄弟级”。

     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. 但是,在这种情况下,预期会出现意想不到的结果。

Just spent 4 hours with this problem. 刚花了4个小时解决这个问题。 Finally realized that you must not use zero as view id . 最终意识到,您不能使用零作为视图ID You would think that it is allowed as NO_ID == -1, but things tend to go haywire if you give it to your view... 您可能会认为它被允许为NO_ID == -1,但是如果您给出自己的观点,事情就会变得一团糟。

Android 22 minimal runnable example Android 22最低可运行示例

在此处输入图片说明

Source: 资源:

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

Works with the default project generated by android create project ... . 适用于android create project ...生成的默认项目。 GitHub repository with minimal build code . 带有最少构建代码的GitHub存储库

call 呼叫

tv1.setId(1) 

after

tv1.setText("A");

Try: 尝试:

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

This approach with ViewGroup.MarginLayoutParams worked for me: 这种使用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);
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);
    }

}

If you really want to layout manually, i'd suggest not to use a standard layout at all. 如果您真的想手动布局,我建议您完全不要使用标准布局。 Do it all on your own, here a kotlin example: 您可以自行完成所有操作,这里有一个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)
    }
}

This might give you an idea how this could work 这可能会让您知道如何操作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM