Override certain attributes of a custom control

谁都会走 提交于 2019-12-12 01:28:48

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!