【问题标题】:Override certain attributes of a custom control覆盖自定义控件的某些属性
【发布时间】:2015-07-02 15:28:11
【问题描述】:

假设在一个 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>

在 app/styles.xml 中:

<style name="CreditCardInputField">
    <item name="android:layout_margin">50dp</item>
</style>

我得到的结果是应用程序中的样式完全覆盖了库中的样式。 IE。我丢失了backgroundtextStyle 属性,同时正确地覆盖了layout_margin。这不是我想要的,我想保留在库中定义的 backgroundtextStyle。有没有可能,如果有,怎么做?

编辑:澄清一下,我不想直接在应用程序中使用该样式,只需要使用该样式的库中的自定义控件。因此,在应用程序中创建新样式(使用库中的父项)实际上没有任何效果。

【问题讨论】:

  • 你能再解释一下吗? 只有库中使用样式的自定义控件是什么意思?
  • 当然。我的目标是创建一个设置,其中库可以提供自定义控件,并且应用程序可以在一定程度上自定义该控件。我正在考虑不同的方法,包括通过&lt;declare-styleable&gt; 自定义属性和覆盖样式。显然,样式在此设置中效果不佳。
  • 我不确定这是否可能,据我所知,当您创建样式 CreditCardInputField 时,它会以这种方式工作,因为它没有覆盖特定属性,而是覆盖了完整样式.由于名称相同,libs/style 中的样式对应用程序不可见。 (类似于任何其他编程语言中的范围)

标签: android android-library android-styles


【解决方案1】:

在 app/styles.xml 中为您的样式使用不同的名称,并将其他样式设为父样式。

<style name="newCreditCardInputField" parent="CreditCardInputField">
    <item name="android:layout_margin">50dp</item>
</style>

这将在恢复背景和 textStyle 时覆盖您的 layout_margin。

【讨论】:

    【解决方案2】:

    我找到了一种通过自定义属性实现我想要的方法。不像样式那样方便,但更灵活。简而言之,在库中声明自定义属性,在控件的代码中读取它们,在应用程序中提供。这是几乎完整的代码,也许这会对某人有所帮助:

    在 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"/>
    

    【讨论】:

      【解决方案3】:

      你应该使用父 attribute 例如:

      <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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-06-06
        • 1970-01-01
        • 2018-05-08
        • 2014-08-18
        • 1970-01-01
        • 2016-11-08
        • 2015-12-21
        相关资源
        最近更新 更多