问题
Let's say there's a custom control and related style in an Android library project. The application that uses this library wants to override certain attributes of that control, while inheriting the others. In my current approach, I have the following code:
In library/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>
In app/styles.xml:
<style name="CreditCardInputField">
<item name="android:layout_margin">50dp</item>
</style>
The result I have is that the style from the app completely overrides the style from the library. I.e. I lose the background
and textStyle
properties, while correctly overriding the layout_margin
. This is not what I want, I want to keep the background
and textStyle
as they're defined in library. Is it possible, and, if yes, how?
EDIT: To clarify, I don't want to use the style directly in the app, only the custom control from the library that uses the style. Therefore creating a new style in the app (with a parent from the library) does effectively nothing.
回答1:
Use a different name to your style in app/styles.xml and make the other style as it's parent.
<style name="newCreditCardInputField" parent="CreditCardInputField">
<item name="android:layout_margin">50dp</item>
</style>
This will override your layout_margin while restoring background and textStyle.
回答2:
I've found a way to achieve what I want through the custom attributes. Not as convenient as with a style, but more flexible. In short, declare custom attributes in the library, read them in the control's code, provide in the app. Here's the almost complete code, maybe this will help someone:
In lib/values/attrs.xml (custom attributes are declared here):
<?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>
In lib/layout/credit_card_view.xml (this is the custom control's layout):
<?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>
In lib/java/TestView.java (the custom control itself):
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);
}
}
And finally in app/layout/main_activity.xml, custom control's usage and configuration:
<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"/>
回答3:
You should use parent attribute e.g.:
<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>
来源:https://stackoverflow.com/questions/31188744/override-certain-attributes-of-a-custom-control