プログラムでビューにIDを割り当てるにはどうすればよいですか?


202

XMLファイルでは、のようにビューにIDを割り当ててandroid:id="@+id/something"を呼び出すfindViewById()ことができますが、プログラムでビューを作成する場合、IDを割り当てるにはどうすればよいですか?

setId()デフォルトの割り当てと同じではないと思います。setId()余分です。

誰かが私を訂正できますか?


1
サブセット:ユニークなIDを生成する方法:stackoverflow.com/questions/1714297/...
チロSantilliは郝海东冠状病六四事件法轮功

回答:


521

Androidのid概要

Android idは、ビューを識別するために一般的に使用される整数です。これidは、XML(可能な場合)およびコード(プログラムで)を介して割り当てることができます。これidViewInflater(を使用するなどsetContentView)によって生成されたXML定義のへの参照を取得するのに最も役立ちます。

id介して割り当てXML

  • android:id="@+id/somename の属性をビュー"に追加します。
  • アプリケーションが構築されると、android:idはコードで使用するために一意 intに割り当てられます。
  • " somename"(実質的には定数)を使用して、コードでandroid:idint値を参照しますR.id.
  • これintはビルドごとに変わる可能性があるため、package.name / からIDコピーしないでください。「somename」を使用してください。gen/R.javaR.id.
  • (また、XMLでにid割り当てられたPreferenceは、がをPreference生成するときに使用されませんView。)

idコードを介して割り当てる(プログラムで)

  • int idを使用して手動でsを設定するsomeView.setId();
  • int正でなければなりませんが、それ以外それはあなたが望むものは何でもすることができarbitrary-される(これは恐ろしいであれば読み続けます。)
  • たとえば、アイテムを表す複数のビューを作成して番号を付ける場合、それらのアイテム番号を使用できます。

idSの一意性

  • XML-割り当てられたidは一意になります。
  • コードが割り当てられたidは一意である必要ありませ
  • コードが割り当てられたidは、(理論的には)が割り当てられたと競合するXML可能性idがあります。
  • これらの競合idするは、正しくクエリされた場合(読み続けて)は問題になりません。

競合するidsが問題ではない場合(および理由)

  • findViewById(int)、指定したビューからビュー階層全体で深さ優先で反復的に繰り返しView、一致するで最初に見つかったものを返しますid
  • 階層でidXML定義の前に割り当てられたコードが割り当てられていない限りidfindViewById(R.id.somename)は常にそのようにXML定義のビューを返しますid

動的ビューの作成および割り当てID

  • レイアウトXMLでは、空のViewGroupをで定義しますid
  • などLinearLayoutandroid:id="@+id/placeholder"
  • コードを使用して、プレースホルダーViewGroupViews を入力します。
  • 必要な場合は、id各ビューに便利なを割り当てます。
  • placeholder.findViewById(convenientInt);を使用してこれらの子ビューをクエリします。

  • View.generateViewId()一意のIDを生成できるAPI 17が導入されました。

周りのビューへの参照を保持することを選択した場合は、それらを使用してインスタンス化し、getApplicationContext()各参照をnullに設定してくださいonDestroy。どうやら漏れたActivity(それは後に破壊されている上にぶら下がっは)無駄な..です:)

android:idコードで使用するためにXML を予約する

View.generateViewId() 一意のIDを生成するAPI 17が導入されました。(これを指摘してくれたtake-chances-make-changesに感謝します。)*

ViewGroupXMLで定義できない場合(または定義したくない場合)、IDをXMLで予約して、一意であることを確認できます。

ここで、values / ids.xmlはカスタムを定義しますid

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="reservedNamedId" type="id"/>
</resources>

次に、ViewGroupまたはViewが作成されたら、カスタムIDをアタッチできます

myViewGroup.setId(R.id.reservedNamedId);

矛盾するid

難読化の例としてわかりやすくするためidに、舞台裏で競合がある場合に何が起こるかを調べてみましょう。

layout / mylayout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/placeholder"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
</LinearLayout>

競合をシミュレートするために、最新のビルドにR.id.placeholder@+id/placeholder)のint 12 ..が割り当てられているとしましょう

次に、MyActivity.javaはいくつかの追加ビューをプログラムで(コードを介して)定義します。

int placeholderId = R.id.placeholder; // placeholderId==12
// returns *placeholder* which has id==12:
ViewGroup placeholder = (ViewGroup)this.findViewById(placeholderId);
for (int i=0; i<20; i++){
    TextView tv = new TextView(this.getApplicationContext());
    // One new TextView will also be assigned an id==12:
    tv.setId(i);
    placeholder.addView(tv);
}

したがってplaceholder、新しいTextViewの1 つには、id12の!しかし、プレースホルダの子ビューをクエリする場合、これは実際には問題ではありません。

// Will return a generated TextView:
 placeholder.findViewById(12);

// Whereas this will return the ViewGroup *placeholder*;
// as long as its R.id remains 12: 
Activity.this.findViewById(12);

*そんなに悪くない


9
これに加えて、類似のソリューションをコーディングする場合、競合しないIDのAPI> 17でView.generateViewId()を認識すると便利です
AllDayAmazing

findViewByIdは深さ優先探索を行うため、「XMLで定義されたIDの上に割り当てられたコード割り当てIDが階層内にない限り」は技術的に正しくありません。「上」ではなく「前」です。
Karu、2014年

Android開発者ツールの最近のバージョンでは、プログラムでIDを任意の値に設定すると、コンパイラエラーとしてフラグが立てられます。値は実際のリソースIDであることが期待されています。
ThomasW 2017年

5年前に答えたときもそうだったと思いids.xmlます。そのため、カスタムIDをで定義する必要がありました。本当に任意のIDの場合は、View.generateViewId()(API 17)を使用します。(見逃した場合は、要点を明確にしてください。)
CodeShane 2017年

>(また、XMLで設定に割り当てられたIDは、設定がそのビューを生成するときに使用されません。)非常に興味があります。私のコードはPreferenceDialogFragmentCompatそれから継承しているようR.idです。この方法では、IDでビューを見つけることができません。
UrK

6

View.setId(integer)このためだけに使用できます。XMLでは、文字列IDを設定している場合でも、これは整数に変換されます。このため、Views プログラムで追加する任意の(正の)整数を使用できます。

Viewドキュメントによると

識別子は、このビューの階層内で一意である必要はありません。識別子は正の数でなければなりません。

したがって、任意の正の整数を使用できますが、この場合、同等のIDを持つビューがいくつか存在する可能性があります。階層内のビューを検索する場合は、いくつかのキーオブジェクトを使用してsetTagを呼び出すと便利です。

この回答のクレジット。


5

はい。setId(value)任意の(正の)整数値を使用して任意のビューで呼び出し、を使用して親コンテナでそれを見つけることができますfindViewById(value)setId()異なる兄弟ビューに対して同じ値で呼び出すことは有効ですがfindViewById()、最初のビューのみが返されることに注意してください。


1
ゼロより大きい整数を使用する必要があることに注意してください。
Peter Ajtai

ただし、findViewById(int)は、指定したビューからのビュー階層を再帰的に反復し、最初の回答で指定された一致するIDで見つかった最初のビューが最も正確です。
Aniket Thakur 2013

ええ、findViewById既知の祖先を呼び出すことはパフォーマンス上の理由から良い考えですが、正しいIDを持つ子が存在する場合、直接の子が見つかるとは限りません。
Karu、2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.