LayoutInflater.inflate
Документация не совсем ясно мне о цели attachToRoot
параметра.
attachToRoot : должна ли завышенная иерархия быть привязана к корневому параметру? Если false, root используется только для создания правильного подкласса LayoutParams для корневого представления в XML.
Может кто - то пожалуйста , объясните более подробно, а именно то , что вид корня, и , возможно , показать пример изменения в поведении между true
и false
ценностей?
android
android-layout
android-view
layout-inflater
Джефф Аксельрод
источник
источник
Ответы:
СЕЙЧАС ИЛИ НЕ СЕЙЧАС
Основное различие между «третьим» параметром attachToRoot, равным true или false, заключается в следующем.
true: добавить дочернее представление к родителю ПРЯМО СЕЙЧАС
false: добавить дочернее представление к родителю НЕ СЕЙЧАС .
Добавьте это позже. `
Это позже, когда вы используете, например, для
parent.addView(childView)
Распространенным заблуждением является то, что если параметр attachToRoot имеет значение false, то дочернее представление не будет добавлено к родительскому. НЕПРАВИЛЬНО
В обоих случаях дочерний вид будет добавлен в parentView. Это просто вопрос времени .
эквивалентно
БОЛЬШОЕ НЕТ-НЕТ
Вы никогда не должны передавать attachToRoot как true, если вы не несете ответственности за добавление дочернего представления к родительскому.
Например, при добавлении фрагмента
если вы передадите третий параметр как true, вы получите IllegalStateException из-за этого парня.
Поскольку вы уже добавили дочерний фрагмент в onCreateView () по ошибке. Вызов add скажет вам, что дочернее представление уже добавлено к родителю. Отсюда IllegalStateException .
Здесь вы не несете ответственности за добавление childView, за это отвечает FragmentManager. Так что всегда передавайте false в этом случае.
ПРИМЕЧАНИЕ: я также читал, что parentView не получит childView touchEvents, если attachToRoot имеет значение false. Но я не проверял это все же.
источник
FragmentManager
, спасибо!Если задано значение true, то при накачке макета он будет автоматически добавлен в иерархию представлений группы ViewGroup, указанной во втором параметре, как дочерний элемент. Например, если корневой параметр был
LinearLayout
то ваше завышенное представление будет автоматически добавлено как потомок этого представления.Если установлено значение false, то ваш макет будет раздут, но не будет привязан ни к какому другому макету (поэтому он не будет отображаться, получать сенсорные события и т. Д.).
источник
false
дляattachToRoot
во время моего фрагментаonCreateView
. Это решило проблему , и все же макет фрагмента виден и активен, несмотря на ваш ответ. Что происходит здесь?true
, представление присоединяется ко 2-му параметру, который являетсяcontainer
, но затем вы говорите, что фрагмент автоматически присоединяется изonCreateView()
, так что, насколько я понимаю, третий параметр бесполезен и должен быть установленfalse
всегда?onCreateView
. Если вы надуваете дополнительные макеты в этом корневом представлении или надуваете в другом контексте (например, в действии), тогда это полезно.Кажется, что в ответах много текста, но нет кода, поэтому я решил восстановить этот старый вопрос на примере кода, в нескольких ответах, которые упоминали люди:
Что это на самом деле означает в коде (что понимают большинство программистов):
Обратите внимание, что предыдущий код добавляет макет
R.layout.child_view
как дочерний элементMyCustomLayout
из-заattachToRoot
paramtrue
и назначает параметры макета родительского элемента точно таким же образом, как если бы я использовалaddView
программно, или как если бы я делал это в xml:Следующий код объясняет сценарий при передаче
attachRoot
какfalse
:В предыдущем коде вы указали, что хотите
myView
быть его собственным корневым объектом и не привязывать его к какому-либо родительскому объекту, позже мы добавили его как часть,LinearLayout
но на мгновение это было автономное (не родительское) представление.То же самое происходит с фрагментами, вы можете добавить их в уже существующую группу и стать ее частью, или просто передать параметры:
Чтобы указать, что это будет его собственный корень.
источник
Документации и двух предыдущих ответов должно быть достаточно, только некоторые мысли от меня.
inflate
Метод используется для накачивания файлов макета. С этими раздутыми макетами у вас есть возможность прикрепить их непосредственно к родителюViewGroup
или просто накачать иерархию представления из этого файла макета и работать с ним вне обычной иерархии представления.В первом случае
attachToRoot
параметр должен быть установлен вtrue
(или намного проще использоватьinflate
метод, который принимает файл макета и родительский кореньViewGroup
(неnull
)). В этом случаеView
возвращается просто то,ViewGroup
что было передано в методе,ViewGroup
к которому будет добавлена раздутая иерархия представления.Для второго варианта возвращается
View
кореньViewGroup
из файла макета. Если вы помните наше последнее обсуждение вопроса оinclude-merge
паре, это одна из причинmerge
ограничения (когда файл макета сmerge
именем root завышен, необходимо указать родительский элемент иattachedToRoot
установить его значениеtrue
). Если у вас был файл макета с корневымmerge
тегом и онattachedToRoot
был установлен,false
тоinflate
метод не будет ничего возвращать, посколькуmerge
не имеет эквивалента. Также, как сказано в документации,inflate
версия сattachToRoot
установленным на от родительского. Это важно в некоторых случаях, наиболее заметно с потомками , подкласса , для которогоfalse
важна значением, поскольку вы можете создать иерархию представлений с правильнымиLayoutParams
AdapterView
ViewGroup
addView()
набор методов не поддерживается. Я уверен, что вы помните, используя эту строку вgetView()
методе:Эта строка гарантирует, что накачанный
R.layout.row_layout
файл имеет правильное значениеLayoutParams
изAdapterView
подкласса, установленного в его корнеViewGroup
. Если вы этого не сделаете, у вас могут возникнуть проблемы с файлом макета, если корнем был aRelativeLayout
.TableLayout/TableRow
Также есть специальное и важно ,LayoutParams
и вы должны убедиться , что мнения в них правильноLayoutParams
.источник
Я сам был также путать о том, что была реальная цель
attachToRoot
вinflate
методе. После небольшого изучения пользовательского интерфейса я наконец получил ответ:родитель:
в данном случае это виджет / макет, который окружает объекты представления, которые вы хотите накачать с помощью findViewById ().
attachToRoot:
присоединяет представления к их родителю (включает их в родительскую иерархию), поэтому любое событие касания, которое получают представления, также будет перенесено в родительское представление. Теперь дело за родителем, хочет ли он развлекать эти события или игнорировать их. если установлено значение false, они не добавляются как прямые потомки родителя, и родитель не получает никаких событий касания от представлений.
Надеюсь, что это устраняет путаницу
источник
Я написал этот ответ, потому что даже пройдя несколько страниц StackOverflow, я не смог четко понять, что означает attachToRoot. Ниже приведен метод inflate () в классе LayoutInflater.
Посмотрите на activity_main.xml файл, button.xml расположение и MainActivity.java файла , который я создал.
activity_main.xml
button.xml
MainActivity.java
Когда мы запустим код, мы не увидим кнопку в макете. Это потому, что наш макет кнопки не добавляется в основной макет действия, так как attachToRoot имеет значение false.
LinearLayout имеет метод addView (View view), который можно использовать для добавления Views в LinearLayout. Это добавит макет кнопки в основной макет действия и сделает кнопку видимой при запуске кода.
Давайте удалим предыдущую строку и посмотрим, что произойдет, если мы установим attachToRoot в значение true.
Снова мы видим, что расположение кнопок видно. Это связано с тем, что attachToRoot напрямую прикрепляет раздутый макет к указанному родителю. Который в данном случае является корневым LinearLayout. Здесь нам не нужно добавлять представления вручную, как в предыдущем случае с помощью метода addView (View view).
Почему люди получают IllegalStateException, если для attachToRoot установлено значение true для фрагмента.
Это связано с тем, что для фрагмента вы уже указали, где разместить макет фрагмента в файле активности.
Добавить (интермедиат родитель, фрагмент фрагмент) добавляет фрагмент , который имеет его расположение к родительскому макету. Если мы установим attachToRoot как true, вы получите IllegalStateException: указанный дочерний элемент уже имеет родителя. Поскольку макет фрагмента уже добавлен в родительский макет в методе add ().
Вы всегда должны передавать false для attachToRoot, когда вы раздуваете фрагменты. FragmentManager является задачей добавления, удаления и замены фрагментов.
Вернемся к моему примеру. Что делать, если мы делаем оба.
В первой строке LayoutInflater присоединяет макет кнопки к корневому макету и возвращает объект View, который содержит тот же макет кнопки. Во второй строке мы добавляем тот же объект View в родительский корневой макет. Это приводит к тому же исключению IllegalStateException, которое мы видели с фрагментами (у указанного дочернего элемента уже есть родительский элемент).
Имейте в виду, что существует другой перегруженный метод inflate (), который по умолчанию устанавливает attachToRoot в значение true.
источник
Существует много путаницы в этой теме из-за документации для метода inflate ().
В общем, если для attachToRoot установлено значение true, то файл макета, указанный в первом параметре, раздувается и присоединяется к ViewGroup, указанной во втором параметре, в тот момент времени. Когда attachToRoot имеет значение false, файл макета из первого параметра раздувается и возвращается как вид, и любое вложение вида происходит в другое время.
Это, вероятно, мало что значит, если вы не видите много примеров. При вызове LayoutInflater.inflate () внутри метода onCreateView фрагмента вы захотите передать false для attachToRoot, потому что действие, связанное с этим фрагментом, фактически отвечает за добавление представления этого фрагмента. Если вы надуваете вручную и добавляете представление в другое представление в более поздний момент времени, например, с помощью метода addView (), вы захотите передать false для attachToRoot, потому что вложение приходит позднее.
Вы можете прочитать о нескольких других уникальных примерах, касающихся диалогов и пользовательских представлений, в блоге, который я написал на эту тему.
https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/
источник
attachToRoot
значение true означаетinflatedView
объект будет добавлен в иерархию родительского представления. Таким образом, пользователи могут «видеть» и воспринимать события касания (или любые другие операции пользовательского интерфейса). В противном случае, он только что был создан, не добавлен в какую-либо иерархию представления и, следовательно, не может быть виден или обрабатывать события касания.Для разработчиков iOS, впервые знакомых с Android,
attachToRoot
значение true означает, что вы вызываете этот метод:Если вы пойдете дальше, вы можете спросить: зачем мне передавать родительский вид, если я настроен
attachToRoot
наfalse
? Это связано с тем, что корневому элементу в вашем XML-дереве требуется родительское представление для вычисления некоторых параметров LayoutParams (например, match parent).источник
Когда вы определяете родителя, attachToRoot определяет, хотите ли вы, чтобы инфлятор действительно прикрепил его к родителю или нет. В некоторых случаях это вызывает проблемы, как в ListAdapter, это вызовет исключение, потому что список пытается добавить представление в список, но он говорит, что он уже присоединен. В других случаях, когда вы просто надуваете представление для добавления в Activity, это может быть удобно и сэкономит вам строку кода.
источник
Например, у нас есть
ImageView
, аLinearLayout
и аRelativeLayout
. LinearLayout является дочерним элементом RelativeLayout. Иерархия Представлений будет.и у нас есть отдельный файл макета для ImageView
image_view_layout.xml
Присоединить к корню:
setImageResource(R.drawable.np);
ImageView, вам нужно будет найти его по ссылке родителя, т.е.view.findById()
Не привязывать к корню:
view.setImageResource(R.drawable.np);
без ссылки подобноfindViewById
. Но контейнер указан так, что ImageView получает LayoutParams контейнера, так что вы можете сказать, что ссылка на контейнер только для LayoutParams и ничего больше.источник
attachToRoot Установите в true:
Представьте, что мы указали кнопку в файле макета XML с шириной макета и высотой макета, равными match_parent.
Теперь мы хотим программно добавить эту кнопку в LinearLayout внутри фрагмента или действия. Если наш LinearLayout уже является переменной-членом mLinearLayout, мы можем просто добавить кнопку со следующим:
Мы указали, что хотим накачать кнопку из файла ресурсов макета; Затем мы сообщаем LayoutInflater, что хотим присоединить его к mLinearLayout. Наши параметры макета соблюдаются, потому что мы знаем, что Button добавляется в LinearLayout. Тип параметров макета кнопки должен быть LinearLayout.LayoutParams.
attachToRoot Установите в false (не обязательно использовать false)
Давайте посмотрим, когда вы захотите установить для attachToRoot значение false. В этом случае представление, указанное в первом параметре inflate (), не прикреплено к ViewGroup во втором параметре в данный момент времени.
Вспомните наш пример Button из предыдущего, где мы хотим прикрепить пользовательскую кнопку Button из файла макета к mLinearLayout. Мы по-прежнему можем присоединить нашу кнопку к mLinearLayout, передав false для attachToRoot - мы просто вручную добавим его самостоятельно.
Эти две строки кода эквивалентны тому, что мы написали ранее в одной строке кода, когда мы передали true для attachToRoot. Передавая false, мы говорим, что пока не хотим присоединять наш View к корневой ViewGroup. Мы говорим, что это произойдет в другой момент времени. В этом примере другим моментом времени является просто метод addView (), который используется сразу после инфляции.
Ложный пример attachToRoot требует немного больше работы, когда мы вручную добавляем View в ViewGroup.
attachToRoot Устанавливается в false (false является обязательным).
Когда надувать и возвращать представление фрагмента в onCreateView (), обязательно передайте false для attachToRoot. Если вы передадите значение true, вы получите исключение IllegalStateException, поскольку указанный дочерний элемент уже имеет родителя. Вы должны были указать, где ваш фрагмент будет возвращен в вашу активность. FragmentManager является задачей добавления, удаления и замены фрагментов.
Контейнер root_viewGroup, в котором будет храниться ваш фрагмент в вашей активности, - это параметр ViewGroup, данный вам в onCreateView () вашего фрагмента. Это также ViewGroup, которую вы передаете в LayoutInflater.inflate (). Однако FragmentManager будет обрабатывать присоединение вашего фрагмента к этой ViewGroup. Вы не хотите прикрепить его дважды. Установите attachToRoot в false.
Почему нам в первую очередь предоставляется родительская ViewGroup нашего фрагмента, если мы не хотим присоединять ее в onCreateView ()? Почему метод inflate () запрашивает корневую ViewGroup?
Оказывается, что даже когда мы не сразу добавляем наш недавно надутый View к его родительской ViewGroup, мы все равно должны использовать LayoutParams родителя, чтобы новый View определял его размер и положение всякий раз, когда он в конечном итоге присоединяется.
Ссылка: https://youtu.be/1Y0LlmTCOkM?t=409
источник
Просто поделюсь некоторыми моментами, с которыми я столкнулся, работая над этой темой,
В дополнение к принятому ответу я хочу несколько моментов, которые могут быть полезны.
Таким образом, когда я использовал attachToRoot как true, возвращаемое представление имело тип ViewGroup, т.е. корневую ViewGroup родителя, которая была передана в качестве параметра для метода inflate (layoutResource, ViewGroup, attachToRoot) , а не типа макета, который был передан, но для attachToRoot. как false мы получаем тип, возвращаемый функцией корневого ViewGroup этого layoutResource .
Позвольте мне объяснить на примере:
Если у нас есть LinearLayout в качестве корневого макета, а затем мы хотим добавить TextView в него через функцию inflate .
затем с помощью attachToRoot в качестве истинной функции раздувать возвращает вид типа LinearLayout
в то время как на использование attachToRoot в качестве ложной функции раздувать возвращает вид типа TextView
Надеюсь, что это открытие поможет ...
источник