Применить стиль в пользовательском представлении, где корневой тег макета объединен

У меня есть 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 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)
    }
}

Вот 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>

Здесь есть 2 вещи, на которые следует обратить внимание:

  1. Макет использует тег слияния, чтобы избежать избыточного представления в иерархии представлений.

  2. Крайне важно применить пользовательский стиль. Стиль применяется в исходном xml с использованием синтаксиса style=. Однако, поскольку тег слияния используется для пользовательского представления, это невозможно сделать таким образом.

Я попытался установить стиль следующим образом, но это не сработало:

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

Я предполагаю, что приведенное выше решение должно работать, поскольку третий параметр в конструкторе должен передаваться в стиле.

Другой вариант — установить все свойства программно в init {} моего пользовательского представления, но это противоречит цели объявления стиля в файле стилей.

Каковы мои варианты?




Ответы (1)


В настоящее время существует 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. общедоступное представление (контекстный контекст, атрибуты AttributeSet, int defStyleAttr, int defStyleRes) добавлено на уровне API 21

3-й и 4-й конструкторы вызываются подклассами, если они хотят указать атрибут, содержащий стиль по умолчанию, или стиль по умолчанию напрямую (в случае конструктора с четырьмя аргументами).

Например, конструктор класса Button вызовет эту версию конструктора суперкласса и предоставит R.attr.buttonStyle для defStyleAttr; это позволяет стилю кнопки темы изменять все атрибуты базового представления (в частности, его фон), а также атрибуты класса Button. от документы

Итак, когда вы создаете свое собственное представление и добавляете это представление в XML, андроид всегда будет вызывать второй конструктор, который выглядит так под капотом.

public TextInputLayout(Context context, AttributeSet attrs) {
    this(context, attrs, attr.textInputStyle);
}

Третий аргумент attr.textInputStyle — получение этого конкретного стиля непосредственно из темы приложения.

Итак, для достижения желаемого результата можно сделать следующее.

  1. В 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>
  1. Добавьте в свою 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>

  1. Finally, in your custom view second constructor you pass that attribute as a parameter

    constructor(context: Context, attrs: AttributeSet) : 
      super(
            context,
            attrs,
            R.attr.attribute_name
           )
    

Я надеюсь, что это помогает!

person Ruan_Lopes    schedule 15.11.2019
comment
Работал! Спасибо - person rgv; 16.11.2019
comment
Это для настроек уровня темы, что, если я хочу задать стиль для представления в определенном макете? - person Jimit Patel; 11.12.2020