我在styles.xml中定义了2种样式,现在想将它们应用到一个TextView上。如何使用style="@style/"实现?
无法直接实现,您需要创建一个将两种样式结合在一起的样式。(或者创建一个继承自其中一种样式的样式,并添加第二个样式的额外数据)。
你可以创建一个继承其他样式的样式。
例如:
<style name="Side_Menu_Button" parent="android:attr/buttonStyleSmall">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">match_parent</item>
</style>
侧边菜单按钮继承了buttonStyleSmall的所有属性。
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="@style/padding">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Bold text with padding"
style="@style/text_bold" />
</LinearLayout>
这是一个我成功运用的黑客技巧:
<style name="TextAppearance.Title.App" parent="TextAppearance.AppCompat.Subhead">
<item name="android:textColor">@color/primary_text_default_material_light</item>
</style>
<style name="Custom.TV" parent="TextView.App">
<item name="android:textAppearance">@style/TextAppearance.Other.App</item>
</style>
我知道我已经晚了10年,但我自己遇到了这个问题,并找到了一个解决方法,尽管它是一个相当麻烦的解决方法。
要开始,您需要声明样式属性,以便稍后分配给您的视图。
<declare-styleable name="TextView">
<attr name="style1" format="reference" />
<attr name="style2" format="reference" />
<attr name="style3" format="reference" />
<attr name="style4" format="reference" />
<attr name="style5" format="reference" />
</declare-styleable>
您可以在布局中的视图中添加这些样式属性,例如:
<TextView
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nice_cta"
app:style1="@style/Background_Blue"
app:style2="@style/CallToAction.Primary"
app:style3="@style/Button_Layout" />
ViewInflater
,并将其分配给应用程序主题下的viewInflaterClass
。在这个ViewInflater
内部,您需要收集styleable属性,并将它们合并到theme
中,如下所示:class MultiStyleViewInflater : MaterialComponentsViewInflater() {
// override the creators of any view you want to have multiple styles
override fun createTextView(context: Context, attrs: AttributeSet?): AppCompatTextView {
// create context if needed and set the attributes as usual
return super.createTextView(createContextIfMultiStyle(context, attrs), attrs)
}
// override fun anyOtherView as needed ...
private fun createContextIfMultiStyle(context: Context, attrs: AttributeSet?): Context {
// get our handy custom attributes
val styleAttributes = context.obtainStyledAttributes(attrs, R.styleable.TextView)
// collect the styles added to the view
val styles = extractStyles(styleAttributes)
// create the custom ContextThemeWrapper only if the view has a custom multi style attribute
val createdContext = if (styles.any { it != 0 }) {
// create a theme, add styles and create the wrapper using the theme
val theme = context.resources.newTheme()
theme.applyValidStyles(styles)
ContextThemeWrapper(context, theme)
} else {
// or just return the original context
context
}
// don't forget to call this!
styleAttributes.recycle()
return createdContext
}
private fun extractStyles(styleAttributes: TypedArray) = listOf(
// the zero values help us determine if we have a custom style added at all
styleAttributes.getResourceId(R.styleable.TextView_style1, 0),
styleAttributes.getResourceId(R.styleable.TextView_style2, 0),
styleAttributes.getResourceId(R.styleable.TextView_style3, 0),
styleAttributes.getResourceId(R.styleable.TextView_style4, 0),
styleAttributes.getResourceId(R.styleable.TextView_style5, 0)
)
private fun Resources.Theme.applyValidStyles(styles: List<Int>) {
// adding styles that actually exist. note we force update duplicate attributes
styles.filterNot { it == 0 }.forEach { this.applyStyle(it, true) }
}
}
ViewInflater
以使其生效:<item name="viewInflaterClass">com.agostonr.multistyleapp.utils.MultiStyleViewInflater</item>
如果你构建应用程序,这样做后,样式将显示在编辑器中以及在设备上运行的应用程序中。
有关更详细的说明,请参阅我在Medium上撰写的文章。