在合并布局根标签的自定义视图中应用样式
Apply Style in custom view where layout root tag is merge
我有一个 TextInputLayout
带有自定义样式,需要大量重复使用,因此我试图将其变成自定义视图。
这是要重复使用的 xml:
<com.google.android.material.textfield.TextInputLayout
style="@style/TextInputLayoutAppearance"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
TextInputLayoutAppearance
是我在styles.xml
中创建的自定义样式
这是我的自定义视图的 Class:
class OutlinedTextInput @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextInputLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.view_outlined_textinput, this, true)
}
}
这是我从上面的原始 xml 改编而来的 view_outlined_textinput
,用于自定义视图:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="com.google.android.material.textfield.TextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</merge>
这里有 2 点需要注意:
布局使用合并标签来避免视图层次结构中的冗余视图。
应用自定义样式至关重要。使用 style= 语法在原始 xml 中应用样式。但是,由于合并标签用于自定义视图,因此不能那样做。
我试过如下设置样式,但没用:
class OutlinedTextInput @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.style.TextInputLayoutAppearance
) : TextInputLayout(context, attrs, defStyleAttr) {
我认为上述解决方案应该有效,因为构造函数中的第三个参数是传入样式。
另一种选择是在我的自定义视图的 init {}
中以编程方式设置所有属性,但这违背了在样式文件中声明样式的目的。
我有哪些选择?
目前一个视图有4个构造器
public 视图(上下文上下文)-> 从代码创建视图时使用的简单构造函数。
public View (Context context, AttributeSet attrs) -> 从 XML
膨胀视图时调用的构造函数
public View (Context context, AttributeSet attrs, int defStyleAttr) -> 从 XML 执行 inflation 并应用 class-specific来自主题属性的基本样式。
public View (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) 添加于API level 21
如果子classes 想要指定包含默认样式的属性,或者直接指定默认样式(在四参数构造函数的情况下),则调用第 3 和第 4 个构造函数
For example, a Button class's constructor would call this version of the super class constructor and supply R.attr.buttonStyle for defStyleAttr; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes. from the docs
因此,当您创建自定义视图并将该视图添加到 XML 时,android 将始终调用第二个构造函数,它在幕后看起来像这样
public TextInputLayout(Context context, AttributeSet attrs) {
this(context, attrs, attr.textInputStyle);
}
第三个参数 attr.textInputStyle
是直接从应用程序主题中获取特定样式。
因此,要获得您正在寻找的结果,您可以执行以下操作。
- 在你的
attrs.xml
添加 <attr name="attribute_name" format="reference" />
例如。 attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="attribute_name" format="reference" />
</resources>
- 在文件中添加你的AppTheme
style.xml
<item name="attribute_name">@style/your_style</item>
例如。 style.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
...
<item name="attribute_name">@style/your_style</item>
...
</style>
最后,在您的自定义视图第二个构造函数中,将该属性作为参数传递
constructor(context: Context, attrs: AttributeSet) :
super(
context,
attrs,
R.attr.attribute_name
)
希望对您有所帮助!
我有一个 TextInputLayout
带有自定义样式,需要大量重复使用,因此我试图将其变成自定义视图。
这是要重复使用的 xml:
<com.google.android.material.textfield.TextInputLayout
style="@style/TextInputLayoutAppearance"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
TextInputLayoutAppearance
是我在styles.xml
这是我的自定义视图的 Class:
class OutlinedTextInput @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextInputLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.view_outlined_textinput, this, true)
}
}
这是我从上面的原始 xml 改编而来的 view_outlined_textinput
,用于自定义视图:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="com.google.android.material.textfield.TextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</merge>
这里有 2 点需要注意:
布局使用合并标签来避免视图层次结构中的冗余视图。
应用自定义样式至关重要。使用 style= 语法在原始 xml 中应用样式。但是,由于合并标签用于自定义视图,因此不能那样做。
我试过如下设置样式,但没用:
class OutlinedTextInput @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.style.TextInputLayoutAppearance
) : TextInputLayout(context, attrs, defStyleAttr) {
我认为上述解决方案应该有效,因为构造函数中的第三个参数是传入样式。
另一种选择是在我的自定义视图的 init {}
中以编程方式设置所有属性,但这违背了在样式文件中声明样式的目的。
我有哪些选择?
目前一个视图有4个构造器
public 视图(上下文上下文)-> 从代码创建视图时使用的简单构造函数。
public View (Context context, AttributeSet attrs) -> 从 XML
膨胀视图时调用的构造函数
public View (Context context, AttributeSet attrs, int defStyleAttr) -> 从 XML 执行 inflation 并应用 class-specific来自主题属性的基本样式。
public View (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) 添加于API level 21
如果子classes 想要指定包含默认样式的属性,或者直接指定默认样式(在四参数构造函数的情况下),则调用第 3 和第 4 个构造函数
For example, a Button class's constructor would call this version of the super class constructor and supply R.attr.buttonStyle for defStyleAttr; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes. from the docs
因此,当您创建自定义视图并将该视图添加到 XML 时,android 将始终调用第二个构造函数,它在幕后看起来像这样
public TextInputLayout(Context context, AttributeSet attrs) {
this(context, attrs, attr.textInputStyle);
}
第三个参数 attr.textInputStyle
是直接从应用程序主题中获取特定样式。
因此,要获得您正在寻找的结果,您可以执行以下操作。
- 在你的
attrs.xml
添加<attr name="attribute_name" format="reference" />
例如。 attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="attribute_name" format="reference" />
</resources>
- 在文件中添加你的AppTheme
style.xml
<item name="attribute_name">@style/your_style</item>
例如。 style.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
...
<item name="attribute_name">@style/your_style</item>
...
</style>
最后,在您的自定义视图第二个构造函数中,将该属性作为参数传递
constructor(context: Context, attrs: AttributeSet) : super( context, attrs, R.attr.attribute_name )
希望对您有所帮助!