假设在Android库项目中有一个自定义控件和相关样式。使用此库的应用程序希望覆盖该控件的某些属性,同时继承其他属性。在我目前的方法中,我有以下代码:
在库/styles.xml:中
<style name="CreditCardInputField">
<item name="android:layout_margin">10dp</item>
<item name="android:background">@drawable/border</item>
<item name="android:textStyle">bold|italic</item>
</style>
应用程序内/styles.xml:
<style name="CreditCardInputField">
<item name="android:layout_margin">50dp</item>
</style>
我得到的结果是,应用程序中的样式完全覆盖了库中的样式。即,我丢失了background
和textStyle
属性,同时正确地覆盖了layout_margin
。这不是我想要的,我想保留库中定义的background
和textStyle
。这可能吗?如果可能,怎么做?
编辑:为了澄清,我不想直接在应用程序中使用样式,只想使用库中使用该样式的自定义控件。因此,在应用程序中创建一个新样式(使用库中的父样式)实际上没有任何作用。
在app/styles.xml中为您的样式使用不同的名称,并将另一个样式作为其父样式。
<style name="newCreditCardInputField" parent="CreditCardInputField">
<item name="android:layout_margin">50dp</item>
</style>
这将在恢复背景和文本样式时覆盖您的layout_margin。
我找到了一种通过自定义属性实现我想要的东西的方法。没有样式那么方便,但更灵活。简而言之,在库中声明自定义属性,在控件的代码中读取它们,在应用程序中提供。以下是几乎完整的代码,也许这会对某人有所帮助:
在lib/values/attrs.xml中(此处声明自定义属性):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="test_view">
<attr name="field_margins" format="dimension">50dp</attr>
<attr name="field_background" format="reference">@drawable/border</attr>
<attr name="name_field_hint" format="reference"/>
<attr name="number_field_hint" format="reference"/>
</declare-styleable>
</resources>
在lib/layout/credit_card_view.xml(这是自定义控件的布局)中:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<EditText
style="@style/CreditCardInputField"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
style="@style/CreditCardInputField"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</merge>
在lib/java/TestView.java(自定义控件本身)中:
public class TestView extends LinearLayout {
public TestView(Context context) {
super(context);
}
public TestView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.test_view, 0, 0);
int margins = (int)a.getDimension(R.styleable.test_view_field_margins, 0f);
int background = a.getResourceId(R.styleable.test_view_field_background, R.drawable.border);
int nameFieldHint = a.getResourceId(R.styleable.test_view_name_field_hint, R.string.name_field_hint_lib);
int numberFieldHint = a.getResourceId(R.styleable.test_view_number_field_hint, R.string.number_field_hint_lib);
a.recycle();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.credit_card_view, this, true);
setOrientation(LinearLayout.VERTICAL);
setGravity(Gravity.CENTER_VERTICAL);
TextView title = (TextView) getChildAt(0);
title.setHint(nameFieldHint);
title.setBackgroundResource(background);
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(context, attrs);
p.setMargins(margins, margins, margins, margins);
title.setLayoutParams(p);
TextView number = (TextView) getChildAt(1);
number.setHint(numberFieldHint);
number.setBackgroundResource(background);
number.setLayoutParams(p);
}
}
最后在app/layout/main_activity.xml中,自定义控件的使用和配置:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
...>
<com.example.testlibrary.TestView
custom:field_margins="20dp"
custom:field_background="@drawable/field_background"
custom:name_field_hint="@string/name_field_hint"
custom:number_field_hint="@string/number_field_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
您应该使用父属性,例如:
<style name="CreditCardInputField" parent="parentStyle">
<item name="android:layout_margin">10dp</item>
<item name="android:background">@drawable/border</item>
<item name="android:textStyle">bold|italic</item>
</style>