Передача параметров макета всем дочерним элементам в составном представлении - PullRequest
0 голосов
/ 28 апреля 2020

Я создал следующий составной вид, чтобы представить небольшой раздел, который будет использоваться на страницах с подробностями. Он предназначен для многоразового использования контейнера со стилизованным заголовком и должен по умолчанию устанавливать правильные поля для всех его дочерних элементов (чтобы я мог изменить это поле в 1 месте и не беспокоиться об этом в другом месте).

import android.content.Context
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import androidx.core.view.children
import com.developerpaul123.mhwdatabase.R
import kotlinx.android.synthetic.main.component_detail_section.view.*
import kotlin.math.roundToInt

public class DetailSectionLayout : LinearLayout {

    private var leftMarginDp: Float = 0f
    private var verticalMarginDp: Float = 0f

    constructor(context: Context, title: String?) : super(context) {
        init(context, title)
    }

    constructor(context: Context, attributes: AttributeSet?) : super(context, attributes) {
        val attrTitle: String? = getSectionTitleAttribute(context, attributes)
        init(context, attrTitle)
    }

    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr) {
        val attrTitle: String? = getSectionTitleAttribute(context, attrs)
        init(context, attrTitle)
    }

    private fun getSectionTitleAttribute(
        context: Context,
        attributes: AttributeSet?
    ): String? {
        val attrs = context.obtainStyledAttributes(attributes, R.styleable.DetailSectionLayout)

        val attrTitle: String?
        try {
            attrTitle = attrs.getString(R.styleable.DetailSectionLayout_detailSectionTitle)
        } finally {
            attrs.recycle()
        }
        return attrTitle
    }

    private fun init(context: Context, title: String?) {
        val inflater = LayoutInflater.from(context);
        inflater.inflate(R.layout.component_detail_section, this, true)

        leftMarginDp =
            TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 28f, resources.displayMetrics)
        verticalMarginDp =
            TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 10f, resources.displayMetrics)

        orientation = VERTICAL

        layoutParams = LayoutParams(
            LayoutParams.MATCH_PARENT,
            LayoutParams.WRAP_CONTENT
        )
        (layoutParams as LayoutParams).setMargins(
            leftMarginDp.roundToInt(),
            verticalMarginDp.roundToInt(),
            0,
            verticalMarginDp.roundToInt()
        )

        setTitleText(title)

        if (childCount > 0) {
            for (child in children) {
                child.layoutParams = layoutParams
            }
        }
    }

    fun setTitleText(title: String?) {
        detail_section_title.text = title
    }

    override fun addView(child: View?) {
        child?.apply {
            val params = layoutParams as LinearLayout.LayoutParams
            // force margins
            params.setMargins(
                leftMarginDp.roundToInt(),
                verticalMarginDp.roundToInt(),
                0,
                verticalMarginDp.roundToInt()
            )
            child.layoutParams = params
        }
        super.addView(child)
    }
}

И раздуваемый макет:

<?xml version="1.0" encoding="utf-8"?>

<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"
    android:layout_marginStart="28dp"
    android:layout_marginTop="10dp"
    android:layout_marginBottom="10dp"
    android:orientation="vertical"
    tools:parentTag="android.widget.LinearLayout">

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/detail_section_title"
        style="@style/TextAppearance.App.CategoryHeadline"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        tools:text="Detail Section" />
</merge>

У меня проблема в том, что поля по умолчанию, которые я устанавливаю, не передаются детям должным образом. «Хак», который я сделал, переопределив addView(), работал для детей, которые добавляются программно в Kotlin, но это не влияет на детей, которые добавляются в XML, например:

<com.developerpaul123.mhwdatabase.components.DetailSectionLayout
    android:id="@+id/detailSectionLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:detailSectionTitle="Camps">

    <com.google.android.material.textview.MaterialTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Test"/>
</com.developerpaul123.mhwdatabase.components.DetailSectionLayout>

Результат компоновки следующий:

enter image description here

Где «Test» - это MaterialTextView, добавленный в XML, а другие представления - это представления, которые раздуваются во время выполнения и вставляются в макет программно. Обратите внимание, что последние имеют правильное начальное поле (выровненное по названию Camps).

Мой вопрос: возможно ли выполнить sh то, что я ищу, и правильно передать параметры поля всем дочерним элементам? по умолчанию, включая как те, что добавлены в XML, так и те, которые добавлены в код?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...