我有一个名为
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 并且还有一个自定义分隔线。但是当我在某些活动中包含自定义视图时,它似乎根本不知道它(是它应该是什么样子,以及它实际上是什么样子),所以我必须手动设置分隔符和包含此自定义视图时的方向。
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 中创建自定义视图以及从包含的布局继承样式和属性进行。我将分别解决每个问题:
第一个问题:继承属性 在自定义
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
),并且它们与您要应用它们的特定视图类型的属性和特性兼容。