问题描述
出于某种原因,我想获取布局文件中使用的小部件的完整类名。有些小部件按类全名显示,如android.support.constraint.ConstraintLayout
,而有些默认小部件则不是。
例如,在下面的代码中,TextView
实际上对应于android.widget.TextView
。
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
所有这些在XML文件中具有缩写形式的小部件类型标记都来自android.widget
包?或者这些依赖项确定在哪些文件中?
推荐答案
首先我要说的是,仅仅通过检查布局并不能真正确定标记将导致的确切运行时类型。LayoutInflater
是处理将布局转换为运行时View
层次结构的(基类)类,它的Factory
接口&插件和设置,以及Android的开放继承组件设计,提供了几个可以修改或完全覆盖默认布局膨胀的点。此外,没有技术要求任何特定名称产生View
的任何特定子类型。
但是,通常您可以安全地进行一些基本假设--例如,<Button>
标记可能会导致android.widget.Button
的实例或其子类--否则事情可能很快就会变得毫无意义和崩溃。大多数情况下,进行这些膨胀修改是为了增强或扩展基本UI类型,而不是大幅更改标准过程。
也就是说,平台充气程序将按顺序在以下四个包中查找任何不包含句点(.
)的View
名称,这是用于区分缩写类名和完全限定类名的唯一标准:
android.widget
,其中可以找到大多数可用平台View
类。android.webkit
,用于<WebView>
。android.app
,对于<ActivityView>
,仅供系统使用,对SDK隐藏。android.view
、<View>
、<SurfaceView>
、<TextureView>
以及更多隐藏项。
View
到(可能)多个Factory
实现,并且它不会费心查看其中是否有任何一个返回一个。如果没有,则充气器将检查上述包,将每个包连续添加到缩写名称的前面,并尝试使用Context
的ClassLoader
将结果加载为View
子类。
如果缩写名称在这些包中都不存在,您最终将得到一个重新抛出的ClassNotFoundException
(包装在InflateException
中),并显示一条消息Didn't find class "android.view.BadLayoutTagName"
,表明android.view
确实是最后检查的包。
目前最常见的外部Factory
实现可能来自androidX和Material组件库,这两个库都将用它们自己的扩展类替换许多平台View
,因此您至少应该意识到这一点。
androidX的Factory
将View
创建委托给一个helper类AppCompatViewInflater
,该类进行以下替换:
标记名: | 在包androidx.appcompat.widget 中: |
---|---|
AutoCompleteTextView |
AppCompatAutoCompleteTextView |
Button |
AppCompatButton |
CheckBox |
AppCompatCheckBox |
CheckedTextView |
AppCompatCheckedTextView |
EditText |
AppCompatEditText |
ImageButton |
AppCompatImageButton |
ImageView |
AppCompatImageView |
MultiAutoCompleteTextView |
AppCompatMultiAutoCompleteTextView |
RadioButton |
AppCompatRadioButton |
RatingBar |
AppCompatRatingBar |
SeekBar |
AppCompatSeekBar |
Spinner |
AppCompatSpinner |
TextView |
AppCompatTextView |
ToggleButton |
AppCompatToggleButton |
材料组件库构建在androidX上,它使用自己的子类MaterialComponentsViewInflater
进一步定制了AppCompatViewInflater
,从而覆盖了上面的几个替换:
标记名: | 包中com.google.android.material : |
---|---|
AutoCompleteTextView |
textfield.MaterialAutoCompleteTextView |
Button |
button.MaterialButton |
CheckBox |
checkbox.MaterialCheckBox |
RadioButton |
radiobutton.MaterialRadioButton |
TextView |
textview.MaterialTextView |
最后,我想提一下,还有各种不是用于
View
的其他标记,这些标记通常由LayoutInflater
或Factory
使用。由于您自己处理这些布局,因此您可能需要确定这些布局对您的特定目标意味着什么。<include>
,用于reusing complete layouts。<merge>
,用于reusing layout "inners", without an enclosing parent。<requestFocus>
,布局后尝试设置焦点。<tag>
,用于向Layout XML中的View
添加键控标签(仅适用于棒棒糖及更高版本)。<blink>
,您可能永远看不到的Easter egg。<fragment>
,实际由Activity
作为其LayoutInflater
的私有Factory2
处理。
<view>
标记--小写的v
--它必须有一个class
属性(无前缀),该属性的值指定所需的View
类(缩写或完整)。此替代格式的存在是为了允许嵌套类,因为它们的名称将包含$
字符,这在XML标记名称中是不允许的。
这篇关于如何在Android布局XML文件中获取Widget的全类名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!