Созданный класс привязки, который принимает только LayoutInflater в качестве единственного аргумента - PullRequest
0 голосов
/ 03 мая 2020

сгенерированный класс привязки из библиотеки Android Data Binding имеет разные версии метода inflate: тот, который выглядит как обычный LayoutInflater.inflate метод, который принимает viewGroup и attachToRoot параметр, и тот, который принимает только LayoutInflater и ничего больше.

enter image description here

Документация не объясняет разницу между этими двумя и, к сожалению, Android Studio не позволяет мне просматривать исходный код inflate, чтобы я мог выяснить, какие значения он использует внутри для viewGroup и attachToRoot. Размещая фрагменты на экране, я не замечаю никакой разницы между ними. Когда я использую его для элементов RecyclerView, метод inflate, который принимает только LayoutInflater, не размещает элементы должным образом.

Поэтому мой вопрос: какие значения для viewGroup и attachToRoot делают этот метод используется внутренне, и уместно ли использовать его во фрагменте onCreateView?

Ответы [ 2 ]

1 голос
/ 03 мая 2020

Какие значения для viewGroup и attachTo Root внутренне использует этот метод?

Параметры зеркально отражают параметры на LayoutInflater, где root: ViewGroup описывается как

Необязательный вид, который будет родительским для сгенерированной иерархии (если attachTo Root имеет значение true), или просто объект, который предоставляет набор значений LayoutParams для root возвращаемая иерархия (если attachTo Root имеет значение false.) Это значение может быть null.

Источник: LayoutInflater docs , emphasis mine.

Аргумент root используется для генерации LayoutParams из атрибутов layout_* XML для раздутого представления. Каждый макет может понимать другой набор атрибутов макета и определять другой набор значений по умолчанию. Вот почему вы всегда должны проходить root. Единственное место, где это невозможно, - это надувание диалоговых представлений.

Метод с одним параметром в привязке не обеспечивает макет root, поэтому LayoutParams для раздутого представления не генерируется при этом точка. Другими словами, inflate(inflater) == inflate(inflater, null, false).

Если представление не имеет LayoutParams , когда вы присоединяете его , его новый родительский макет сгенерирует значение по умолчанию, используя generateDefaultLayoutParams.

Если вы следите за тем, что generateDefaultLayoutParams делает в RecyclerView, он делегируется менеджеру раскладки . Теперь посмотрите на значение по умолчанию LayoutParams, предоставленное LinearLayoutManager:

@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
    return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);
}

Как правило, если вы планируете иметь вертикальный список, вы должны установить android:layout_width="match_parent" для элементов. Но когда вы присоединяете вид без LayoutParams к RecyclerView, он получает оба измерения равными wrap_content. Вот почему ваш макет выглядит неправильно при накачке root == null.


Уместно ли использовать [метод с одним параметром inflate] в фрагменте onCreateView?

Однопараметрический инфлятор можно использовать для надувания диалоговых представлений, где нет родительского / контейнера / root представления.

Как правило, вы присоединяете фрагмент к FrameLayout или FragmentContainerView (что расширяет FrameLayout). FrameLayout генерирует LayoutParams с match_parent шириной и высотой. Если это нормально для вашего фрагмента, вы можете использовать однопараметрический метод inflate для вашей привязки.

В противном случае всегда используйте предоставленного / известного родителя для генерации правильного LaoyutParams. Не полагайтесь на значение по умолчанию LayoutParams, предоставляемое контейнером, к которому вы прикрепляете представление, даже если это тот же макет. Вы определили некоторые параметры макета в XML, и вы хотите, чтобы они соблюдались.

Помните, что если вы удерживаете ссылку на привязку, происходит некоторая церемония жизненного цикла фрагмента.

Вот моя текущая настройка с фрагментами + просмотр привязок:

// Nullable reference so we can use it later and clear it later.
private var binding: ExampleFragmentBinding? = null

private fun requireBinding() = checkNotNull(binding)

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
    // Respect the XML layout params.
    val binding = ExampleFragmentBinding.inflate(inflater, container, false)
    this.binding = binding
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val binding = requireBinding()
    // Do stuff with the views.
}

override fun onDestroyView() {
    // Detach view hierarchy reference from fragment, which may prevent memory leaks.
    this.binding = null

    super.onDestroyView()
}
0 голосов
/ 03 мая 2020

Если вы используете Kotlin, используйте эту версию, только если layoutId заранее неизвестно:

private lateinit var viewModel: MyViewModel

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val binding : MyFragmentBinding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false)
    viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
    binding.myViewModel = viewModel
    binding.lifecycleOwner = this
    return binding.root
}

, в противном случае используйте сгенерированный метод инфляции Binding класса:

lateinit var binding: MyFragmentBinding 
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val binding = MyFragmentBinding.inflate(inflater, container, false)
    return binding.root
}

Обновление:

Итак, мой вопрос: какие значения для viewGroup и attachTo Root внутренне использует этот метод и целесообразно ли использовать его в onCreateView фрагмента?

Когда вы вызываете inflate только с параметром inflater, null и false являются значениями по умолчанию, переданными ie. когда вы делаете:

val binding: MyFragmentBinding = MyFragmentBinding.inflate(inflater)

это похоже на:

 val binding: MyFragmentBinding = MyFragmentBinding.inflate(inflater, null, false)
...