プログラムでRelativeLayoutのビューをレイアウトする方法は?


234

(XMLによる宣言ではなく)プログラムで次のことを達成しようとしています。

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

言い換えると、2番目をTextView最初の1 番目の下に表示するにはどうすればよいですか?

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

プログラムでアイテムを相対的に配置するには、sechastainへのすべてのクレジットがIDを割り当てる必要があります。

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のルールを設定する前にchildviewでrequestLayout()を呼び出すと、動作します。これが誰かのお
役に立てば幸い

誰かがこれに引き続き従う場合:ビューのコレクションがある場合、1つずつbelow追加していて、アイテムに設定されているビューの1つが既に追加されているかどうか確信が持てません。正しく?私の理解でaddViewは、レイアウトが再レンダリングされる原因となるため、親戚がまだ追加されていないアイテムに対してそれを行うと、そのIDのアイテムがまだ存在しないため、クラッシュします。
Megakoresh

1
set(id)は、generateViewId()とともに使用する必要があります。APIレベル17で追加されました。set(id)は、setId(int)での使用に適した値を生成します。この値は、R.idのaaptによってビルド時に生成された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)

注意:レイアウトコールバックからレイアウトを変更しないでください。ビューが実際のサイズを取得するのはこのためです。ただし、その場合、予期しない結果が予想されます。


paramsをビューに設定し、そのビューをその親ビューにすべて1行のコード(parentLayout.addView(myView, lp)で追加できるとは思いもしませんでした。私はいつもそれを2行のコードで行いました。ありがとうございました!
Matt

これは私にとってはうまくいき、多くの助けとなりましたが、子供を何かの下に揃えてから、その子供のために上のマージンを設定する方法はありますか?または、下にあるものに下のマージンを設定できますか?それは正しく調整されますか?
Jacob Varner、2014

確かにあります。setMargins(左、上、右、下)を使用してマージンを設定できます(残念ながら、プログラムによるAPIはXMLほど快適ではありません)。それはLayoutParamsにあります。パディングはビューのプロパティであり、レイアウトパラメータではないことに注意してください。
Meymann 2014

29

この問題に4時間費やしただけです。最後に、ビュー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か?試してみましたが、3つ目TextViewが欠落しています。
Zizheng Wu 2017

7

コール

tv1.setId(1) 

tv1.setText("A");

私が尋ねる場合、その理由は何ですか?問題がありますが、ImageViewとTextViewを使用しているので、ImageViewで.setId()を呼び出すのはいつですかと思います。
ジョシュア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 2014年

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.