使用包含标签的 Android 数据绑定

Posted

技术标签:

【中文标题】使用包含标签的 Android 数据绑定【英文标题】:Android Data Binding using include tag 【发布时间】:2016-01-02 00:59:12 【问题描述】:

更新说明:

上面的例子工作正常,因为1.0-rc4版本修复了需要不必要变量的问题。

原问题:

我完全按照documentation 中的描述进行操作,但它不起作用:

ma​​in.xml:

<layout xmlns:andr...
    <data>
    </data>
       <include layout="@layout/buttons"></include>
....

buttons.xml:

<layout xmlns:andr...>
    <data>
    </data>
    <Button
        android:id="@+id/button"
        ...." />

MyActivity.java:

 ... binding = DataBindingUtil.inflate...
binding.button; ->cannot resolve symbol 'button'

如何获取按钮?

【问题讨论】:

喜欢更新developer.android.com/topic/libraries/data-binding/expressions 【参考方案1】:

问题在于包含的布局没有被认为是数据绑定布局。为了让它充当一个,你需要传递一个变量:

buttons.xml:

<layout xmlns:andr...>
  <data>
    <variable name="foo" type="int"/>
  </data>
  <Button
    android:id="@+id/button"
    ...." />

ma​​in.xml:

<layout xmlns:andr...
...
   <include layout="@layout/buttons"
            android:id="@+id/buttons"
            app:foo="@1"/>
....

那么就可以通过buttons字段间接访问按钮了:

MainBinding binding = MainBinding.inflate(getLayoutInflater());
binding.buttons.button

从 1.0-rc4(刚刚发布)开始,您不再需要该变量。您可以将其简化为:

buttons.xml:

<layout xmlns:andr...>
  <Button
    android:id="@+id/button"
    ...." />

ma​​in.xml:

<layout xmlns:andr...
...
   <include layout="@layout/buttons"
            android:id="@+id/buttons"/>
....

【讨论】:

1.0-rc4 现在修复了需要不必要变量的问题。您现在可以简单地使用:&lt;include layout="@layout/buttons" android:id="@+id/buttons"/&gt;。您仍然需要 id 以便它为您生成一个公共字段,以便您可以访问按钮视图。 还有其他人在布局上绑定点击事件时遇到问题吗? 数据绑定包含支持。 developer.android.com/topic/libraries/data-binding/… 这里要记住的要点是获取按钮引用,你需要做binding.id of include tag.button而不是binding.button。我花了一段时间才弄明白。 @NeonWarge 在developer.android.com/topic/libraries/data-binding/… 上有一个完整的示例。它添加了“数据绑定不支持包含作为合并元素的直接子元素”【参考方案2】:

简单的完整示例

只需将id 设置为包含布局,然后使用binding.includedLayout.anyView

此示例有助于将值传递给 &lt;include 并访问代码中包含的视图。

步骤 1

您有 layout_common.xml,想将 String 传递给包含的布局。

您将在布局中创建String 变量并将此String 引用到TextView

<data>
    // declare fields
    <variable
        name="passedText"
        type="String"/>
</data>

<TextView
    android:id="@+id/textView"
    ...
    android:text="@passedText"/> //set field to your view.

第二步

将此布局包含到父布局中。给包含的布局一个 id,以便我们可以在绑定类中使用它。现在您可以将 String passedText 传递给您的 &lt;include 标签。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        ..
        >

        <include
            android:id="@+id/includedLayout"
            layout="@layout/layout_common"
            app:passedText="@@string/app_name" // here we pass any String 
            />

    </LinearLayout>
</layout>
您现在可以在课堂上使用binding.includedLayout.textView

您可以像上面一样将任何变量传递给包含的布局。

ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.includedLayout.textView.setText("text");

注意两种布局(父版和包含)都应该是binding layout,用&lt;layout包裹

【讨论】:

在您的回答中,您以编程方式处理了 setText 事件,而不是 TextView 如果它本来是一个 Button ,那么您将如何处理它的点击事件。我知道以编程方式 binding.includedLayout.button.setOnClickListener 将是替代方案,但是如果我想在 XML 本身中使用 onClick 属性呢? 您可以将OnClickListener 传递给包含的布局。甚至你可以在绑定中传递任何东西。检查这个答案,如果您需要更多帮助,请告诉我。 ***.com/a/51722829/6891563 当我这样做时,我只得到一个空白字段passedText。唯一的区别是我不包含 MainActivity 代码,因为我只想在 中传递字符串资源并保持原样。为什么总是空白? @Elliptica 作为它的数据绑定,我猜passedText 的值应该是ObservableField 或LiveData,否则它永远不会被实际加载,对@Khemraj? 这不会编译。 Error: cannot find symbol【参考方案3】:

只需为您的包含布局设置一个 id

    <include
        android:id="@+id/layout"
        layout="@layout/buttons" />

然后

BUTTONSBINDING binding = yourMainBinding.layout;

BUTTONSBINDING 是 res/layout/buttons.xml

现在:

binding.button.setText("simple_Way");

【讨论】:

【参考方案4】:

另一个有趣的事情是,您可以像这样从活页夹将变量传递给导入的布局:

MainBinding binding = MainBinding.inflate(getLayoutInflater());
binding.buttons.setVariable(BR.varID, variable)

【讨论】:

【参考方案5】:

您可以让您的绑定在您的包含上工作,只需向其中添加一个 ID,如下所示:

<include
            android:id="@+id/loading"
            layout="@layout/loading_layout"
            bind:booleanVisibility="@viewModel.showLoading" />

【讨论】:

【参考方案6】:

您的 xml 文件中似乎有空数据标签,请交叉检查,这是导致不生成包含布局文件的原因

 <data>

</data>

如果你不使用删除这个标签,将解决问题

【讨论】:

【参考方案7】:

我想补充一下,我遇到了类似的问题。 我的问题是变量名称是标题,与 id 名称相同。 没有编译错误。 (不是 100% 确定这是个问题,我也清理了项目)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">
<data>

    <variable
        name="title"
        type="String" />
</data>
...
<androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/title"...>
<androidx.appcompat.widget.AppCompatTextView>
...
</layout>

【讨论】:

【参考方案8】:

只要确保你的包含布局启用了 dataBinding 标签

下面的代码是我在其他布局中包含的布局

<data>

    <variable
        name="backBinding"
        type="String" />

</data>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cl_back"
    android:layout_
    android:layout_
    android:layout_marginStart="@dimen/dimen_30"
    android:layout_marginTop="@dimen/dimen_30"
    android:padding="@dimen/dimen_2"
    app:layout_constraintStart_toStartOf="parent">

    <ImageView
        android:id="@+id/iv_back"
        android:layout_
        android:layout_
        android:contentDescription="@string/back"
        android:src="@drawable/ic_back"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_back"
        style="@style/AidoFTTextStyle"
        android:layout_
        android:layout_
        android:layout_marginStart="@dimen/dimen_10"
        android:text="@string/face_training"
        android:textSize="@dimen/text_20"
        app:layout_constraintBottom_toBottomOf="@id/iv_back"
        app:layout_constraintStart_toEndOf="@id/iv_back"
        app:layout_constraintTop_toTopOf="@id/iv_back" />

</androidx.constraintlayout.widget.ConstraintLayout>

这里我包含在我的主要布局中

<data>

    <variable
        name="viewModel"
        type="com.ingenDynamic.coreaidokotlin.viewModels.VideoCallViewModel" />

</data>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:background="@drawable/aido_main_background"
    tools:context=".ui.aidoVideoCall.ContactActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/back_layout"
        android:layout_
        android:layout_
        android:layout_marginTop="@dimen/dimen_20"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/cl_appBar">

        <include
            android:id="@+id/back"
            layout="@layout/app_back_layout"
            />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

我可以直接访问我包含的布局

binding.backLayout.setOnClickListener finish()

binding.back.tvBack.text = getText(R.string.video_call)

【讨论】:

以上是关于使用包含标签的 Android 数据绑定的主要内容,如果未能解决你的问题,请参考以下文章

来自 Transformation 的数据绑定 LiveData - Android Kotlin

Android 数据绑定不适用于 <merge> 属性

Android 数据绑定库 vs Kotlin Android 扩展

Android基础——框架模式MVVM之DataBinding的实践

Android 数据绑定:如何避免“找不到 KaptTask”警告

Eclipse ADT 项目中的 Android 数据绑定(无 gradle)