Skip to content

Commit cbcb2aa

Browse files
committed
fix: support DataBinding expressions in ImageView android:src attribute
Problem: - When using android:src="@{icon}" with DataBinding, the icon was not displayed - The generated executeBindings() method only contained text binding, missing icon binding Root Cause: - ImageSourceAttributeHandler.supportsValue() rejected DataBinding expressions like "@{icon}" because isSupportedDrawableReference("@{icon}") returned false - This caused android:src to be marked as 'unsupported' instead of 'dataBinding' - As a result, collectDataBindingExpressions() didn't collect the icon binding Solution: - Added isDataBindingExpression() helper to detect @{} and @={} expressions - Modified ImageSourceAttributeHandler.supportsValue() to accept DataBinding expressions - DataBinding expressions are validated at runtime via executeBindings(), not at compile time Impact: - android:src="@{icon}" now correctly generates viewIcon.setImageResource(icon ?: 0) - Other drawable-based attributes can benefit from this pattern if needed
1 parent 697d204 commit cbcb2aa

3 files changed

Lines changed: 96 additions & 0 deletions

File tree

‎compiler-core/src/main/kotlin/com/github/donglua/layoutx2c/registry/ViewRegistry.kt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,10 @@ open class ResourceAwareViewRegistry(
10091009
}
10101010

10111011
override fun supportsValue(node: LayoutNode, parentTagName: String?, attrName: String, value: String): Boolean {
1012+
// DataBinding 表达式会在运行时通过 executeBindings() 处理,不需要在这里验证
1013+
if (isDataBindingExpression(value)) {
1014+
return true
1015+
}
10121016
return isSupportedDrawableReference(value) && supportsResourceReference(value)
10131017
}
10141018

@@ -1924,6 +1928,11 @@ private fun isSupportedThemeAttr(value: String): Boolean {
19241928
return value.startsWith("?attr/") || value.startsWith("?android:attr/")
19251929
}
19261930

1931+
private fun isDataBindingExpression(value: String): Boolean {
1932+
return (value.startsWith("@{") && value.endsWith("}")) ||
1933+
(value.startsWith("@={") && value.endsWith("}"))
1934+
}
1935+
19271936
private fun isSupportedLiteralOrStringReference(value: String): Boolean {
19281937
return !value.startsWith("?") &&
19291938
(value.startsWith("@string/") || !value.startsWith("@"))
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.github.donglua.layoutx2c.codegen
2+
3+
import com.github.donglua.layoutx2c.analyzer.LayoutAnalyzerV2
4+
import com.github.donglua.layoutx2c.parser.XmlLayoutParser
5+
import com.google.common.truth.Truth.assertThat
6+
import org.junit.Test
7+
8+
class ImageViewSrcBindingTest {
9+
10+
private val parser = XmlLayoutParser()
11+
private val analyzer = LayoutAnalyzerV2()
12+
private val generator = BindingFacadeGeneratorV2(
13+
packageName = "com.example.generated",
14+
rPackageName = "com.example"
15+
)
16+
17+
@Test
18+
fun `generates ImageView src binding with Integer variable`() {
19+
val tree = parser.parse(
20+
"""
21+
<layout xmlns:android="http://schemas.android.com/apk/res/android">
22+
<data>
23+
<variable name="icon" type="Integer" />
24+
<variable name="text" type="String" />
25+
</data>
26+
<FrameLayout
27+
android:layout_width="match_parent"
28+
android:layout_height="match_parent">
29+
<ImageView
30+
android:id="@+id/view_icon"
31+
android:layout_width="24dp"
32+
android:layout_height="24dp"
33+
android:src="@{icon}" />
34+
<TextView
35+
android:id="@+id/view_text"
36+
android:layout_width="wrap_content"
37+
android:layout_height="wrap_content"
38+
android:text="@{text}" />
39+
</FrameLayout>
40+
</layout>
41+
""".trimIndent(),
42+
"test_icon_binding"
43+
)
44+
45+
val analyzed = analyzer.analyze(tree.root)
46+
47+
// 验证 android:src 被识别为 dataBindingAttribute
48+
val imageViewNode = analyzed.children[0].children[0] // FrameLayout -> ImageView
49+
assertThat(imageViewNode.dataBindingAttributes).contains("android:src")
50+
assertThat(imageViewNode.unsupportedAttributes).doesNotContain("android:src")
51+
52+
val generated = generator.generate(
53+
analyzedRoot = analyzed,
54+
layoutName = "test_icon_binding",
55+
layoutResId = "R.layout.test_icon_binding",
56+
useFastPath = true,
57+
dataBindingVariables = tree.rootMetadata.dataBindingVariables
58+
).toString()
59+
60+
println("=== Generated code ===")
61+
println(generated)
62+
63+
// Should generate both text and icon bindings in executeBindings()
64+
assertThat(generated).contains("viewText.setText(text ?: \"\")")
65+
assertThat(generated).contains("viewIcon.setImageResource(icon ?: 0)")
66+
}
67+
}

‎test_icon_binding.xml‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<layout xmlns:android="http://schemas.android.com/apk/res/android">
2+
<data>
3+
<variable name="icon" type="Integer" />
4+
<variable name="text" type="String" />
5+
</data>
6+
<FrameLayout
7+
android:layout_width="match_parent"
8+
android:layout_height="match_parent">
9+
<ImageView
10+
android:id="@+id/view_icon"
11+
android:layout_width="24dp"
12+
android:layout_height="24dp"
13+
android:src="@{icon}" />
14+
<TextView
15+
android:id="@+id/view_text"
16+
android:layout_width="wrap_content"
17+
android:layout_height="wrap_content"
18+
android:text="@{text}" />
19+
</FrameLayout>
20+
</layout>

0 commit comments

Comments
 (0)