如何使样式从带有子项的自定义视图类中的布局“继承”?

问题描述 投票:0回答:1

我有一个名为

card.xml
的布局,它是名为
Card.kt
的自定义类的“基本”布局。我有一个适合它的风格(
@style/homepage_block
),它适用于基本情况。

card.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:divider="@drawable/separator_horizontal_empty_10"
    android:showDividers="middle"
    style="@style/homepage_block">

    <!-- i set orientation and divider -->

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/block_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/homepage_block_title">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="TITLE"
            style="@style/text.Header" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

卡.kt

package com.tempapplication.views

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import com.tempapplication.R
import com.tempapplication.databinding.CardBinding


class Card @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0, defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {

    private val binding: CardBinding

    init {
        LayoutInflater.from(context).inflate(R.layout.card, this, true)
        binding = CardBinding.bind(this)
        initAttributes(attrs, defStyleAttr, defStyleRes)
    }

    // i have a custom attribute called title which i use to set the title text
    private fun initAttributes(attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
        if (attrs == null) { return }
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.Card, defStyleAttr, defStyleRes)
        binding.title.text = typedArray.getString(R.styleable.Card_title)
        typedArray.recycle()
    }

    override fun addView(child: View?, params: ViewGroup.LayoutParams?) {
        super.addView(child, params)
    }
}

attrs.xml

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

    <declare-styleable name="Card">
        <attr name="title" format="string" />
    </declare-styleable>

</resources>

所以进一步的问题可以分成两部分。

第一个问题

我可以以某种方式将属性从

card.xml
“继承”到我使用此布局的自定义视图吗?例如,在
card.xml
中,我将线性布局方向设置为 vertical 并且还有一个自定义分隔线。但是当我在某些活动中包含自定义视图时,它似乎根本不知道它(this是它应该是什么样子,以及this它实际上是什么样子),所以我必须手动设置分隔符和包含此自定义视图时的方向。

activity.xml

<com.tempapplication.views.Card
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:divider="@drawable/separator_horizontal_empty_10" 
        android:showDividers="middle"
        app:title="PAGE OF WEEK" >

        <!-- i set orientation and divider even when they are set in card.xml -->

        <include
            layout="@layout/content_week"
            bind:data="@{data.week}"/>

</com.tempapplication.views.Card>

也许我需要将分隔线和方向放入

style
资源中?还是有更优雅的方法来做到这一点?

第二个问题

我有子视图(如上面的代码中包含布局

content_week
)。如何使根线性布局 (
card.xml
) 的初始
@style/homepage_block
样式影响我包含在卡片视图中的子项?例如,我希望 Card 的所有子项都有红色背景,因为
card.xml
中使用了样式资源。有可能吗?

content_week.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable name="data" type="com.tempapplication.modules.HomepageBlockWeekData"/>
    </data>

    <LinearLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:divider="@drawable/separator_horizontal_empty_10"
        android:showDividers="middle"
        style="@style/homepage_block_content">

        <TextView
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:gravity="center_vertical"
            android:text="@{data.title}"
            style="@style/text.Header" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/_1pxh"
            android:backgroundTint="#FFCAC4D0"
            android:background="@drawable/separator" />

        <TextView
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:text="@{data.description}"
            style="@style/text" />
    </LinearLayout>
</layout>
android xml kotlin android-custom-view android-styles
1个回答
0
投票

您的问题围绕在 Android 中创建自定义视图以及从包含的布局继承样式和属性进行。我将分别解决每个问题:

第一个问题:继承属性 在自定义

Card
视图中,您将根据
card.xml
中定义的自定义属性来扩充
attrs.xml
布局并设置属性。但是,直接在 XML 中为
android:orientation
视图的父布局设置的
android:divider
android:showDividers
Card
等属性不会自动应用于自定义视图。

如果您想从父 XML 继承这些属性,您可以通过修改您的

Card
类来实现:

class Card @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0, defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {

    // ... (other code remains the same)

    init {
        LayoutInflater.from(context).inflate(R.layout.card, this, true)
        binding = CardBinding.bind(this)

        // Apply attributes from XML to the custom view
        val attributes = context.obtainStyledAttributes(attrs, R.styleable.Card, defStyleAttr, defStyleRes)
        applyAttributes(attributes)
        attributes.recycle()

        initAttributes(attrs, defStyleAttr, defStyleRes)
    }

    private fun applyAttributes(attrs: TypedArray) {
        val orientation = attrs.getInt(R.styleable.Card_android_orientation, VERTICAL)
        val divider = attrs.getDrawable(R.styleable.Card_android_divider)
        val showDividers = attrs.getInt(R.styleable.Card_android_showDividers, SHOW_DIVIDER_NONE)

        orientation = VERTICAL // Force vertical orientation for the LinearLayout
        divider?.let { setDividerDrawable(divider) }
        setShowDividers(showDividers)
    }

    // ... (other code remains the same)
}

在此代码中,我添加了一个

applyAttributes
函数,该函数从自定义属性获取的
android:orientation
中读取
android:divider
android:showDividers
TypedArray
等属性的值。然后,该函数将这些属性应用到自定义视图,确保继承父 XML 布局中设置的属性。

第二个问题:将样式应用于子视图 如果您希望

Card
自定义视图中的子视图继承 card.xml 布局中定义的样式,则需要为子视图设置适当的样式。在 content_week.xml 中,您可以通过在
style
属性中引用样式来应用样式:

<TextView
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:gravity="center_vertical"
    android:text="@{data.title}"
    style="@style/text.Header" />

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="@dimen/_1pxh"
    android:backgroundTint="#FFCAC4D0"
    android:background="@drawable/separator"
    style="@style/homepage_block_content_separator" />

<TextView
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:text="@{data.description}"
    style="@style/text" />

在这里,我向子视图添加了

style
属性以应用相关样式。确保在样式资源中定义这些样式(
@style/text.Header
@style/homepage_block_content_separator
等),并且它们应该应用于子视图。

请记住,设置样式时,您需要确保样式在样式资源中正确定义 (

styles.xml
),并且它们与您要应用它们的特定视图类型的属性和特性兼容。

© www.soinside.com 2019 - 2024. All rights reserved.