LayoutInflater attachToRootパラメーターはどういう意味ですか?


201

LayoutInflater.inflateドキュメントはまさにの目的について私にクリアされていないattachToRootパラメータ。

attachToRoot:膨張した階層をルートパラメータにアタッチする必要があるかどうか falseの場合、ルートはXMLのルートビューのLayoutParamsの正しいサブクラスを作成するためにのみ使用されます。

誰かがルートビューが何であるかを具体的には、より詳細に説明し、多分間の行動の変化の一例を示してもらえますtrueし、false値を?



回答:


157

今すぐ、または今すぐ

「3番目の」パラメータattachToRootがtrueまたはfalseである主な違いはこれです。

attachToRootを配置すると

true:子ビューを親に今すぐ追加
false:子ビューを親に追加NOT NOW
後で追加します。`

ときにそれがある、後

それは後で使用するときです parent.addView(childView)

よくある誤解は、attachToRootパラメータがfalseの場合、子ビューが親に追加されないことです。WRONG
どちらの場合も、子ビューはparentViewに追加されます。それだけの問題である時間

inflater.inflate(child,parent,false);
parent.addView(child);   

に相当

inflater.inflate(child,parent,true);

A BIG NO-NO
あなたが親に子ビューを追加するための責任を負いませんときは真としてattachToRootを渡すことはありません。
たとえば、フラグメントを追加する場合

public View onCreateView(LayoutInflater inflater,ViewGroup parent,Bundle bundle)
  {
        super.onCreateView(inflater,parent,bundle);
        View view = inflater.inflate(R.layout.image_fragment,parent,false);
        .....
        return view;
  }

3番目のパラメーターをtrueとして渡すと、この男のためにIllegalStateExceptionが発生します。

getSupportFragmentManager()
      .beginTransaction()
      .add(parent, childFragment)
      .commit();

誤ってonCreateView()で子フラグメントをすでに追加しているため。addを呼び出すと、子ビューがすでに親に追加されていることがわかります。したがってIllegalStateExceptionになります。
ここでは、childViewを追加する責任はありません。FragmentManagerが責任を負います。したがって、この場合は常にfalseを渡します。

注: attachToRootがfalseの場合、parentViewはchildView touchEventsを取得しないことも読みました。しかし、私はそれをテストしていません。


6
とくに役立つ部分、特にFragmentManagerありがとうございました!
CybeX 2018

94

trueに設定した場合、レイアウトがインフレートされると、2番目のパラメーターで指定されたViewGroupのビュー階層に子として自動的に追加されます。たとえば、ルートパラメータがだったLinearLayout場合、インフレートされたビューはそのビューの子として自動的に追加されます。

falseに設定すると、レイアウトは膨らみますが、他のレイアウトにはアタッチされません(そのため、描画されず、タッチイベントを受け取りません)。


17
よくわかりません。私は私が読むまで、「指定された子がすでに親エラーが発生しました」になったこの答えに使用するために私を指示し、falseためにattachToRoot私の断片の中にはonCreateView。これは、問題を解決し、まだフラグメントのレイアウトは、あなたの答えにもかかわらず、可視およびアクティブになっている。何が起こっているのかここですか?
Jeff Axelrod 2012

67
FragmentはonCreateViewから返されたレイアウトを自動的にアタッチするためです。したがって、onCreateViewで手動でアタッチすると、ビューは2つの親にアタッチされます(これにより、言及したエラーが発生します)。
ジョセフアール

11
私はここで少し混乱しています、@ JosephEarlに設定したtrue場合、ビューはである2番目のパラメーターにアタッチされますが、containerフラグメントはから自動的にアタッチされると言うonCreateView()ので、私の理解では、3番目のパラメーターは役に立たないので設定する必要がありますfalse常に?
unmultimedio 2014

5
oncreateviewでビューを返すと、自動的にアタッチされます。attachをtrueに設定すると、エラーがスローされます。ただし、スタンドアロンの状況でビューを拡張する場合は、trueに設定することにより、ビューをコンテナーに自動的にアタッチすることを選択できます。私は常に自分でビューを追加するので、私はほとんどtrueに設定しません。
霜降りの素晴らしい14

7
@unmultimedioは、によって返されるルートビューに対してのみ役に立たないonCreateView。ルートビューにさらにレイアウトを展開する場合、または別のコンテキスト(アクティビティなど)で展開する場合は、便利です。
ジョセフアール

36

応答には多くのテキストが含まれているようですが、コードはありません。そのため、私はこの古い質問をコード例で復活させることにしました。

trueに設定した場合、レイアウトがインフレートされると、2番目のパラメーターで指定されたViewGroupのビュー階層に子として自動的に追加されます。

それが実際にコードで意味すること(ほとんどのプログラマが理解すること)は次のとおりです。

public class MyCustomLayout extends LinearLayout {
    public MyCustomLayout(Context context) {
        super(context);
        // Inflate the view from the layout resource and pass it as child of mine (Notice I'm a LinearLayout class).

        LayoutInflater.from(context).inflate(R.layout.child_view, this, true);
    }
}

前のコードはparam is R.layout.child_viewMyCustomLayoutためにレイアウトを子として追加しており、プログラムで使用する場合と同じように、またはxmlでこれを実行した場合とまったく同じ方法で、親のレイアウトparamsを割り当てています。attachToRoottrueaddView

<LinearLayout>
   <View.../>
   ...
</LinearLayout>

次のコードは、attachRootとして渡す場合のシナリオを説明していますfalse

LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setLayoutParams(new LayoutParams(
    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
linearLayout.setOrientation(LinearLayout.VERTICAL);
    // Create a stand-alone view
View myView = LayoutInflater.from(context)
    .inflate(R.layout.ownRootView, null, false);
linearLayout.addView(myView);

前のコードでは、それをmyView独自のルートオブジェクトにしたいこと、親にアタッチしないことを指定しました。後で、それをの一部として追加しましたLinearLayoutが、しばらくの間はスタンドアロン(親なし)ビューでした。

同じことがフラグメントでも発生します。フラグメントを既存のグループに追加して、そのグループの一部にするか、パラメーターを渡すだけです。

inflater.inflate(R.layout.fragment、null、false);

それが自身のルートになることを指定するには。


1
とりわけ、これは最も役に立ちました。
Wahib Ul Haq 2017

26

ドキュメントと前の2つの回答で十分ですが、私からのいくつかの考えだけで十分です。

このinflateメソッドは、レイアウトファイルを拡張するために使用されます。これらのインフレートされたレイアウトでは、親に直接アタッチするViewGroupか、そのレイアウトファイルからビュー階層を単純にインフレートして、通常のビュー階層の外でそれを操作する可能性があります。

最初のケースでは、attachToRootパラメーターをに設定する必要がありますtrue(またはinflate、レイアウトファイルと親ルートViewGroup(以外null)を取得するメソッドを使用する非常に簡単な方法)。この場合、View返されるのは単にViewGroupメソッドで渡されたものでViewGroupあり、インフレートされたビュー階層が追加されます。

2番目のオプションの場合、返されるのViewViewGroupレイアウトファイルのルートです。include-mergeペアの質問からの最後のディスカッションを覚えている場合、これがmergeの制限の理由の1つです(mergeルートがのレイアウトファイルがインフレートされている場合、親を指定し、attachedToRootに設定する必要がありますtrue)。ルートがa mergeタグのレイアウトファイルがあり、それattachedToRootに設定されている場合、同等falseinflateメソッドがないため、メソッドは何も返しmergeません。また、ドキュメントに記載されているように、正しい設定でビュー階層を作成できるため、set to のinflateバージョンは重要です。attachToRootfalseLayoutParams親から。これはいくつかのケースで重要であり、メソッドセットがサポートされていないのAdapterViewサブクラスであるの子で最も顕著です。メソッドでこの行を使用したことを思い出してください。ViewGroupaddView()getView()

convertView = inflater.inflate(R.layout.row_layout, parent, false);

この行は、インフレートされたR.layout.row_layoutファイルがそのルートに設定されLayoutParamsAdapterViewサブクラスから正しいものであることを保証しますViewGroup。これを行わないと、ルートがの場合、レイアウトファイルに問題が発生する可能性がありRelativeLayoutます。にTableLayout/TableRowは特別で重要なものもありLayoutParams、それらのビューが正しいことを確認する必要がありますLayoutParams


18

私自身もattachToRootinflateメソッドの本当の目的が何なのか混乱していました。少しUIを調べた後、ようやく答えがわかりました。

親:

この場合は、findViewById()を使用してインフレートするビューオブジェクトを囲むウィジェット/レイアウトです。

attachToRoot:

ビューを親にアタッチし(親階層にビューを含める)、ビューが受け取るすべてのタッチイベントも親ビューに転送されます。これらのイベントを楽しませるのか、無視するのかは、親の責任です。falseに設定すると、それらは親の直接の子として追加されず、親はビューからタッチイベントを受け取りません。

これで混乱が解消されますように


あなたはいる答えはすでにここで提供されていますstackoverflow.com/questions/22326314/...
ネオンWarge

11

複数のStackOverflowページを通過した後でも、attachToRootの意味を明確に理解できなかったため、この回答を書きました。以下は、LayoutInflaterクラスのinflate()メソッドです。

View inflate (int resource, ViewGroup root, boolean attachToRoot)

activity_main.xmlファイル、button.xmlレイアウト、および作成したMainActivity.javaファイルを見てください。

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</LinearLayout>

button.xml

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    LayoutInflater inflater = getLayoutInflater();
    LinearLayout root = (LinearLayout) findViewById(R.id.root);
    View view = inflater.inflate(R.layout.button, root, false);
}

コードを実行すると、レイアウトにボタンは表示されません。これは、attachToRootがfalseに設定されているため、ボタンレイアウトがメインアクティビティレイアウトに追加されないためです。

LinearLayoutには、ビューをLinearLayoutに追加するために使用できるaddView(View view)メソッドがあります。これにより、ボタンレイアウトがメインアクティビティレイアウトに追加され、コードの実行時にボタンが表示されるようになります。

root.addView(view);

前の行を削除して、attachToRootをtrueに設定するとどうなるか見てみましょう。

View view = inflater.inflate(R.layout.button, root, true);

ここでも、ボタンのレイアウトが表示されています。これは、attachToRootが、指定された親に膨張レイアウトを直接アタッチするためです。この場合はルートのLinearLayoutです。ここでは、前のaddView(View view)メソッドの場合のように手動でビューを追加する必要はありません。

FragmentのattachToRootをtrueに設定すると、なぜIllegalStateExceptionが発生するのですか?

これは、フラグメントの場合、フラグメントレイアウトをアクティビティファイルのどこに配置するかをすでに指定しているためです。

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .add(R.id.root, fragment)
    .commit();

アドオン(int型の親、断片の断片)は、親のレイアウトにそれのレイアウトを持つフラグメントを追加します。attachToRootをtrueに設定すると、IllegalStateException:指定された子にはすでに親があります。フラグメントレイアウトは既にadd()メソッドで親レイアウトに追加されているため。

Fragmentsを膨らませているときは、attachToRootに常にfalseを渡す必要があります。Fragmentを追加、削除、置換するのはFragmentManagerの仕事です。

私の例に戻ります。両方を実行するとどうなるでしょうか。

View view = inflater.inflate(R.layout.button, root, true);
root.addView(view);

1行目で、LayoutInflaterはボタンレイアウトをルートレイアウトにアタッチし、同じボタンレイアウトを保持するViewオブジェクトを返します。2行目では、同じViewオブジェクトを親ルートレイアウトに追加しています。これにより、Fragmentsで見たのと同じIllegalStateExceptionが発生します(指定した子には既に親があります)。

デフォルトでattachToRootをtrueに設定する別のオーバーロードされたinflate()メソッドがあることに注意してください。

View inflate (int resource, ViewGroup root)

シンプルで明確な説明、まさに私が探していたもの!
flyingAssistant

10

inflate()メソッドのドキュメントにより、このトピックには多くの混乱があります。

一般に、attachToRootがtrueに設定されている場合、最初のパラメーターで指定されたレイアウトファイルはインフレートされ、その瞬間に2番目のパラメーターで指定されたViewGroupにアタッチされます。attachToRootがfalseの場合、最初のパラメーターからのレイアウトファイルはインフレートされ、ビューとして返されます。ビューの添付は他のときに発生します。

多くの例を見ない限り、これはおそらくあまり意味がありません。FragmentのonCreateViewメソッド内でLayoutInflater.inflate()を呼び出す場合、そのFragmentに関連付けられているアクティビティが実際にそのFragmentのビューを追加する必要があるため、attachToRootにfalseを渡します。addView()メソッドなどの後の時点で手動でインフレートして別のビューにビューを追加している場合、アタッチメントは後から来るため、attachToRootにfalseを渡します。

ダイアログとカスタムビューに関する他のいくつかのユニークな例については、このトピックについて書いたブログ投稿を参照してください。

https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/


4

attachToRoottrueに設定するinflatedViewと、が親ビューの階層に追加されます。したがって、ユーザーに「見られる」可能性があり、タッチイベント(またはその他のUI操作)を感知できます。それ以外の場合は、作成されただけで、ビュー階層に追加されていないため、表示したり、タッチイベントを処理したりすることはできません。

Androidを初めて使用するiOS開発者のattachToRoot場合、true に設定すると、このメソッドが呼び出されます。

[parent addSubview:inflatedView];

行く場合はさらに、あなたは頼むかもしれない:私は設定している場合、なぜ私が親ビューを渡す必要attachToRootfalse?これは、XMLツリーのルート要素が、LayoutParamを計算するために親ビューを必要とするためです(match parentなど)。


0

親を定義すると、attachToRootは、インフレーターが親に実際にインフレーターをアタッチするかどうかを決定します。ListAdapterのように、これにより問題が発生する場合があります。これは、リストがリストにビューを追加しようとしたが、既にアタッチされていると表示されるため、例外が発生します。アクティビティに追加するためにビューを自分で膨らませている他のケースでは、それは便利で、コードの行を節約できます。


1
良い答えを提供する必要がある明確な画像を提供していません。
Prakhar1001

0

たとえばImageView、a LinearLayout、a 、aがありますRelativeLayout。LinearLayoutはRelativeLayoutの子です。ビュー階層になります。

RelativeLayout
           ------->LinearLayout

また、ImageView用の個別のレイアウトファイルがあります。

image_view_layout.xml

ルートにアタッチ:

//here container is the LinearLayout

    View v = Inflater.Inflate(R.layout.image_view_layout,container,true);
  1. ここでvには、コンテナーレイアウトの参照、つまり、LinearLayoutが含まれています。ImageViewのようなパラメーターを設定するsetImageResource(R.drawable.np);場合は、親の参照で検索する必要があります。view.findById()
  2. vの親はFrameLayoutになります。
  3. LayoutParamsはFrameLayoutになります。

ルートに接続しない:

//here container is the LinearLayout
    View v = Inflater.Inflate(R.layout.image_view_layout,container,false);
  1. ここで、vには参照なしのコンテナーレイアウトが含まれていますが、膨らまされたImageViewへの直接参照が含まれているため、などを参照view.setImageResource(R.drawable.np);せずにパラメーターを設定できますfindViewById。ただし、コンテナーはImageViewがコンテナーのLayoutParamsを取得するように指定されているため、コンテナーの参照はLayoutParamsのためだけであると言えます。
  2. そのため、特に親はnullになります。
  3. LayoutParamsはLinearLayoutになります。

0

attachToRoot trueに設定します。

attachToRootがtrueに設定されている場合、最初のパラメーターで指定されたレイアウトファイルは拡張され、2番目のパラメーターで指定されたViewGroupにアタッチされます。

XMLレイアウトファイルでボタンを指定し、そのレイアウトの幅と高さをmatch_parentに設定したとします。

<Button xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/custom_button">
</Button>

プログラムでこのボタンをFragmentまたはActivity内のLinearLayoutに追加します。LinearLayoutが既にメンバー変数であるmLinearLayoutである場合は、次のようにボタンを追加するだけです。

inflater.inflate(R.layout.custom_button, mLinearLayout, true);

レイアウトリソースファイルからボタンを膨らませることを指定しました。次に、それをmLinearLayoutにアタッチすることをLayoutInflaterに通知します。ButtonがLinearLayoutに追加されることがわかっているため、レイアウトパラメータが尊重されます。ボタンのレイアウトパラメータタイプは、LinearLayout.LayoutParamsである必要があります。

attachToRoot falseに設定(falseを使用する必要はありません)

attachToRootがfalseに設定されている場合、最初のパラメーターで指定されたレイアウトファイルはインフレートされ、2番目のパラメーターで指定されたViewGroupにアタッチされませんが、そのインフレートされたビューは親のLayoutParams取得するため、そのビューを親に正しく合わせることができます。


attachToRootをfalseに設定するタイミングを見てみましょう。このシナリオでは、この時点では、inflate()の最初のパラメーターで指定されたビューは、2番目のパラメーターのViewGroupにアタッチされていません。

レイアウトファイルのカスタムボタンをmLinearLayoutにアタッチする、前のボタンの例を思い出してください。attachToRootにfalseを渡して、ButtonをmLinearLayoutにアタッチすることもできます。後で手動で追加するだけです。

Button button = (Button) inflater.inflate(R.layout.custom_button,    mLinearLayout, false);
mLinearLayout.addView(button);

これらの2行のコードは、attachToRootにtrueを渡したときに、前の1行のコードで記述したものと同等です。falseを渡すことで、まだViewをルートViewGroupにアタッチしたくないと言います。それは別の時点で起こると言っています。この例では、もう1つの時点は、インフレのすぐ下で使用されるaddView()メソッドです。

誤ったattachToRootの例では、手動でビューをViewGroupに追加するときに、もう少し作業が必要です。

attachToRoot Set to false(false is Required)

onCreateView()でフラグメントのビューをインフレートして返す場合、attachToRootには必ずfalseを渡してください。trueを渡すと、指定した子には既に親があるため、IllegalStateExceptionが発生します。フラグメントビューがアクティビティのどこに配置されるかを指定しておく必要があります。Fragmentを追加、削除、置換するのはFragmentManagerの仕事です。

FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment =  fragmentManager.findFragmentById(R.id.root_viewGroup);

if (fragment == null) {
fragment = new MainFragment();
fragmentManager.beginTransaction()
    .add(R.id.root_viewGroup, fragment)
    .commit();
}

アクティビティにフラグメントを保持するroot_viewGroupコンテナは、フラグメントのonCreateView()で指定されたViewGroupパラメータです。また、LayoutInflater.inflate()に渡すViewGroupでもあります。ただし、FragmentManagerは、このViewGroupへのフラグメントのビューのアタッチを処理します。二度つけたくない。attachToRootをfalseに設定します。

public View onCreateView(LayoutInflater inflater, ViewGroup  parentViewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout,     parentViewGroup, false);

return view;
}

onCreateView()でフラグメントをアタッチしたくないのに、なぜ最初からFragmentの親ViewGroupが与えられているのですか?inflate()メソッドがルートViewGroupをリクエストするのはなぜですか?

新しく膨らんだビューをすぐに親のViewGroupに追加していない場合でも、親のLayoutParamsを使用して、最終的にアタッチされるたびに新しいビューがサイズと位置を決定する必要があることがわかります。

リンク:https : //youtu.be/1Y0LlmTCOkM?t=409


0

このトピックの作業中に遭遇したいくつかのポイントを共有するだけで、

受け入れられた答えに加えて、私はいくつかの助けになるかもしれないいくつかの点にしたいです。

したがって、attachToRootをtrueとして使用した場合、返されたビューはViewGroupタイプでした。つまり、inflate(layoutResource、ViewGroup、attachToRoot)メソッドのパラメーターとして渡された親のルートViewGroupで、渡されたレイアウトではなくattachToRootでした。 falseとして、そのlayoutResourceのルートViewGroupの関数の戻り値の型を取得します。

例で説明しましょう:

我々は持っている場合のLinearLayoutとして、ルートレイアウトをし、我々は、追加したいのTextViewを介してでのinflate機能。

次に、attachToRoottrueとして使用すると、関数inflate はタイプLinearLayoutのビューを返します。

attachToRootfalseとして使用している、inflate関数はタイプTextViewのビューを返します

この調査結果がお役に立てば幸いです...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.