0

我添加了一个简单的复合控件,它从 XML 布局加载其布局并实现自己的 XML 属性。

但这仅在此控件位于主包 ( com.myapp) 中时才有效。当我尝试将它移动到一个子包中时,com.myapp.controls事情就开始失败了。

这是定义控件自定义属性的 attrs.xml:

<resources>

    <declare-styleable name="CH2">
        <attr name="textText" format="string" />
    </declare-styleable>

    <declare-styleable name="CH3">
        <attr name="textFex" format="string" />
    </declare-styleable>

</resources>

这是控制 CH2.java,它在 subspackage 中并且不起作用

package com.myapp.controls;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

public class CH2 extends LinearLayout {

    private TextView textView;

    public CH2(Context context) throws Exception {
        super(context);
        init(context, null);
    }

    public CH2(Context context, AttributeSet attrs) throws Exception {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) throws Exception {

        this.setOrientation(LinearLayout.VERTICAL);

        LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        layoutInflater.inflate(com.myapp.R.layout.category_header, this, true);

        View v = findViewById(com.myapp.R.id.chText);
        this.textView = (TextView)v;

        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, com.myapp.R.styleable.CH2);

            String text = a.getString(com.myapp.R.styleable.CH2_textText);
            this.textView.setText(text != null ? text : "<NULL!>");

            a.recycle();        
        }
    }
}

这是 CH3.java 有效:

package com.myapp;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

public class CH3 extends LinearLayout {

    private TextView textView;

    public CH3(Context context) throws Exception {
        super(context);
        init(context, null);
    }

    public CH3(Context context, AttributeSet attrs) throws Exception {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) throws Exception {

        this.setOrientation(LinearLayout.VERTICAL);

        LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        layoutInflater.inflate(com.myapp.R.layout.category_header, this, true);

        View v = findViewById(com.myapp.R.id.chText);
        this.textView = (TextView)v;

        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, com.myapp.R.styleable.CH3);

            String text = a.getString(com.myapp.R.styleable.CH3_textFex);
            this.textView.setText(text != null ? text : "<NULL!>");

            a.recycle();        
        }
    }
}

两个源都使用相同的 category_header.xml。布局加载没有问题。我可以像这样使用两者:

<com.myapp.controls.CH2
    android:id="@+id/cH1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
    myns:textText="Test 1" >
</com.myapp.controls.CH2>

<com.myapp.CH3
    android:id="@+id/cH2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    myns:textFex="Test 2"
    >
</com.myapp.CH3>

如何使 CH2 工作?或者是不可能使用另一个包?

Sidequest:我可以让两个控件使用相同的 XML 属性textText,还是它们总是必须使用不同的属性?或者可声明样式的名称可以与组件名称不同吗?


另一种具有新声明样式的方法:

<declare-styleable name="controls.CH2">
    <attr name="textText" format="string" />
</declare-styleable>

但它似乎不可用。XML 视图总是说Unexpected text found in layout file:,不管我如何使用 CH2:

xmlns:myns="http://schemas.android.com/apk/res/com.myapp"
xmlns:mynsc="http://schemas.android.com/apk/res/com.myapp.controls"
...
<com.myapp.controls.CH2
    android:id="@+id/cH1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
    mynsc:textText="TestTestTest" 
    >        
</com.myapp.controls.CH2>

或者

xmlns:myns="http://schemas.android.com/apk/res/com.myapp"
...
<com.myapp.controls.CH2
    android:id="@+id/cH1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
    myns.controls:textText="TestTestTest" 
    >        
</com.myapp.controls.CH2>
4

1 回答 1

1

我刚刚回到我自己的属性文件,并且没有任何地方引用我的布局所在的非常深的子包...作为旁注,如果您在 attrs 文件中执行此操作,您可以让多个元素使用相同的属性:

<resources>
    <attr name="textText" format="string"/>

    <declare-styleable name="CH2">
        <attr name="textText" />
    </declare-styleable>

    <declare-styleable name="CH3">
        <attr name="textText" />
    </declare-styleable>

</resources>

我对 android 源代码的研究显示了一些示例,它们完全按照您的描述进行操作,它们有一个自定义属性文件指向不同包中的视图类。我看到的唯一明显区别是视图是在布局中声明的,如下所示:

<view
  class="com.myapp.controls.CH2"
  android:id="@+id/cH1"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" >
  myns:textText="Test 1" >
</view>

<view
  class="com.myapp.CH3"
  android:id="@+id/cH2"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" 
  myns:textFex="Test 2"
>
</view>

老实说,我无法告诉您为什么会有所作为……但是每次他们需要自定义属性时,使用的格式

于 2012-04-05T17:01:19.570 回答