在合并布局根标签的自定义视图中应用样式

rgv*_*rgv 4 android-custom-view android-layout android-styles android-textinputlayout android-textinputedittext

我有一个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>
Run Code Online (Sandbox Code Playgroud)

TextInputLayoutAppearance是我在中创建的自定义样式styles.xml

这是我的自定义视图的类:

 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

这是view_outlined_textinput我根据上面的原始 xml 改编的,用于自定义视图:

<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>
Run Code Online (Sandbox Code Playgroud)

这里有件事需要注意:

  1. 布局使用合并标签来避免视图层次结构中的冗余视图。

  2. 应用自定义样式至关重要。使用 style= 语法在原始 xml 中应用样式。但是,由于合并标签用于自定义视图,因此无法以这种方式完成。

我尝试按如下方式设置样式,但没有成功:

class OutlinedTextInput @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.style.TextInputLayoutAppearance
) : TextInputLayout(context, attrs, defStyleAttr) {
Run Code Online (Sandbox Code Playgroud)

我认为上述解决方案应该有效,因为构造函数中的第三个参数是传递样式。

另一种选择是在我的自定义视图中以编程方式设置所有属性init {},但这违背了在样式文件中声明样式的目的。

我有什么选择?

Rua*_*pes 5

目前视图有 4 个构造函数

  1. public View (Context context) -> 从代码创建视图时使用的简单构造函数。

  2. public View (Context context, AttributeSet attrs) -> 从 XML 扩充视图时调用的构造函数

  3. public View (Context context, AttributeSet attrs, int defStyleAttr) -> 从 XML 执行膨胀并从主题属性应用特定于类的基本样式。

  4. public View (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)在 API 级别 21 中添加

如果子类想要指定包含默认样式的属性,或者直接指定默认样式(在四参数构造函数的情况下),则第三个和第四个构造函数由子类调用

例如,Button 类的构造函数将调用此版本的超类构造函数,并为 defStyleAttr 提供 R.attr.buttonStyle;这允许主题的按钮样式修改所有基本视图属性(特别是其背景)以及 Button 类的属性。从文档

因此,当您创建自定义视图并将该视图添加到 XML 中时,android 将始终调用第二个构造函数,其底层如下所示

public TextInputLayout(Context context, AttributeSet attrs) {
    this(context, attrs, attr.textInputStyle);
}
Run Code Online (Sandbox Code Playgroud)

第三个参数attr.textInputStyle是直接从应用程序主题获取特定样式。

因此,要实现您正在寻找的结果,您可以执行以下操作。

  1. 在你的attrs.xml添加中<attr name="attribute_name" format="reference" />

例如。属性.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="attribute_name" format="reference" />
</resources>
Run Code Online (Sandbox Code Playgroud)
  1. 在文件中添加您的AppThemestyle.xml <item name="attribute_name">@style/your_style</item>

例如。样式.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>
Run Code Online (Sandbox Code Playgroud)

  1. 最后,在自定义视图的第二个构造函数中,将该属性作为参数传递

    constructor(context: Context, attrs: AttributeSet) : 
      super(
            context,
            attrs,
            R.attr.attribute_name
           )
    
    Run Code Online (Sandbox Code Playgroud)

我希望它有帮助!