Skip to content

Commit a388449

Browse files
committed
新增对<include />的支持,不支持在标签内使用theme
1 parent 2911afb commit a388449

File tree

6 files changed

+144
-4
lines changed

6 files changed

+144
-4
lines changed

FastInflate/src/main/java/com/dreamgyf/android/plugin/fastinflate/helper/CommonFastInflateHelper.kt

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import android.annotation.SuppressLint
44
import android.content.Context
55
import android.content.res.Resources
66
import android.util.AttributeSet
7+
import android.util.TypedValue
78
import android.view.LayoutInflater
89
import android.view.View
10+
import android.view.ViewGroup
11+
import com.dreamgyf.android.plugin.fastinflate.FastInflate
912
import com.dreamgyf.android.plugin.fastinflate.exception.FastInflateException
1013
import org.xmlpull.v1.XmlPullParser
1114

@@ -102,6 +105,101 @@ object CommonFastInflateHelper : IFastInflateHelper {
102105
ta.recycle()
103106
}
104107

108+
private val tempTypedValue by lazy {
109+
TypedValue()
110+
}
111+
112+
private val ATTRS_INCLUDE by lazy {
113+
intArrayOf(
114+
android.R.attr.id,
115+
android.R.attr.visibility
116+
).apply {
117+
sort()
118+
}
119+
}
120+
121+
private val INDEX_INCLUDE_ID by lazy {
122+
ATTRS_INCLUDE.binarySearch(android.R.attr.id)
123+
}
124+
125+
private val INDEX_INCLUDE_VISIBILITY by lazy {
126+
ATTRS_INCLUDE.binarySearch(android.R.attr.visibility)
127+
}
128+
129+
private const val TAG_MERGE = "merge"
130+
131+
override fun parseInclude(
132+
parser: XmlPullParser,
133+
context: Context,
134+
parent: View,
135+
attrs: AttributeSet
136+
) {
137+
if (parent !is ViewGroup) {
138+
throw FastInflateException("<include /> can only be used inside of a ViewGroup")
139+
}
140+
141+
var layout = attrs.getAttributeResourceValue(null, "layout", 0)
142+
if (layout == 0) {
143+
val value = attrs.getAttributeValue(null, "layout")
144+
if (value == null || value.isEmpty()) {
145+
throw FastInflateException(
146+
"You must specify a layout in the"
147+
+ " include tag: <include layout=\"@layout/layoutID\" />"
148+
)
149+
}
150+
151+
layout = getResId(
152+
value.substring(1),
153+
"attr",
154+
context.packageName
155+
)
156+
}
157+
158+
if (layout != 0 && context.theme.resolveAttribute(layout, tempTypedValue, true)) {
159+
layout = tempTypedValue.resourceId
160+
}
161+
162+
if (layout == 0) {
163+
val value = attrs.getAttributeValue(null, "layout")
164+
throw FastInflateException(
165+
"You must specify a valid layout "
166+
+ "reference. The layout ID " + value + " is not valid."
167+
)
168+
}
169+
170+
FastInflate.from(context).inflate(layout, parent, true)
171+
172+
val childParser = context.resources.getLayout(layout)
173+
advanceToRootNode(childParser)
174+
val childRootNodeName = childParser.name
175+
176+
// 非 <merge /> 标签
177+
if (childRootNodeName != TAG_MERGE) {
178+
val includeView = parent.getChildAt(parent.childCount - 1)
179+
180+
val ta = context.obtainStyledAttributes(attrs, ATTRS_INCLUDE)
181+
val id = ta.getResourceId(INDEX_INCLUDE_ID, View.NO_ID)
182+
val visibility = ta.getInt(INDEX_INCLUDE_VISIBILITY, -1)
183+
ta.recycle()
184+
185+
try {
186+
val params = parent.generateLayoutParams(attrs)
187+
includeView.layoutParams = params
188+
} catch (_: Exception) {
189+
}
190+
191+
if (id != View.NO_ID) {
192+
includeView.id = id
193+
}
194+
195+
when (visibility) {
196+
0 -> includeView.visibility = View.VISIBLE
197+
1 -> includeView.visibility = View.INVISIBLE
198+
2 -> includeView.visibility = View.GONE
199+
}
200+
}
201+
}
202+
105203
override fun callOnFinishInflate(view: View) {
106204
val clz = View::class.java
107205
val method = clz.getDeclaredMethod("onFinishInflate")

FastInflate/src/main/java/com/dreamgyf/android/plugin/fastinflate/helper/IFastInflateHelper.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ interface IFastInflateHelper {
4040
return CommonFastInflateHelper.parseViewTag(parser, view, attrs)
4141
}
4242

43+
fun parseInclude(parser: XmlPullParser, context: Context, parent: View, attrs: AttributeSet) {
44+
return CommonFastInflateHelper.parseInclude(parser, context, parent, attrs)
45+
}
46+
4347
fun callOnFinishInflate(view: View) {
4448
CommonFastInflateHelper.callOnFinishInflate(view)
4549
}

FastInflatePlugin/src/main/java/com/dreamgyf/android/plugin/fastinflate/plugin/FastInflateLayoutGenerator.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ object FastInflateLayoutGenerator {
107107
.addStatement(
108108
"if (root == null || !attachToRoot) { throw %T(\"%L\") }",
109109
fastInflateExceptionClz,
110-
"<merge /> can be used only with a valid ViewGroup root and attachToRoot=true"
110+
"<merge·/>·can·be·used·only·with·a·valid·ViewGroup·root·and·attachToRoot=true"
111111
)
112112
.addStatement("inflateChildren(parser, root, context, attrs)")
113113
} else {
@@ -123,10 +123,11 @@ object FastInflateLayoutGenerator {
123123
.addStatement("inflateChildren(parser, temp, context, attrs)")
124124
.addStatement("if (root != null && attachToRoot) { root.addView(temp, params) }")
125125
.addStatement("if (root == null || !attachToRoot) { result = temp }")
126-
.addStatement("return result!!")
127126
}
128127

129-
inflateFunBuilder.addStatement("} finally { parser.close() }")
128+
inflateFunBuilder
129+
.addStatement("return result!!")
130+
.addStatement("} finally { parser.close() }")
130131

131132
return inflateFunBuilder.build()
132133
}
@@ -194,7 +195,9 @@ object FastInflateLayoutGenerator {
194195
.addStatement("%T.parseViewTag(parser, parent, attrs)", helperClz)
195196
.addStatement("%T.consumeChildElements(parser)", helperClz)
196197
} else if (nodeName == TAG_INCLUDE) {
197-
//TODO
198+
funSpecBuilder
199+
.addStatement("%T.parseInclude(parser, context, parent, attrs)", helperClz)
200+
.addStatement("%T.consumeChildElements(parser)", helperClz)
198201
} else if (nodeName == TAG_MERGE) {
199202
funSpecBuilder.addStatement(
200203
"throw %T(\"<merge /> must be the root element\")",

Sample/src/main/res/layout/activity_main.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,15 @@
4949

5050
</FrameLayout>
5151

52+
<include
53+
android:id="@+id/layout_include_normal"
54+
layout="@layout/layout_include_normal"
55+
android:layout_width="match_parent"
56+
android:layout_height="wrap_content"
57+
app:layout_constraintBottom_toBottomOf="parent" />
58+
59+
<include
60+
android:id="@+id/layout_include_merge"
61+
layout="@layout/layout_include_merge" />
62+
5263
</androidx.constraintlayout.widget.ConstraintLayout>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<merge xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto">
4+
5+
<TextView
6+
android:layout_width="wrap_content"
7+
android:layout_height="wrap_content"
8+
android:layout_gravity="center"
9+
android:text="This is merge include layout"
10+
app:layout_constraintBottom_toBottomOf="parent" />
11+
12+
</merge>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="match_parent">
5+
6+
<TextView
7+
android:layout_width="wrap_content"
8+
android:layout_height="wrap_content"
9+
android:layout_gravity="center"
10+
android:text="This is normal include layout" />
11+
12+
</FrameLayout>

0 commit comments

Comments
 (0)