Reputation: 5505
I have added an easy compound control which loads its layout from a XML layout and implements own XML attributes.
But this only works while this control is in the main package (com.myapp
). When I try to move it into a subpackage like com.myapp.controls
things begin to fail.
This is the attrs.xml to define the control custom attributes:
<resources>
<declare-styleable name="CH2">
<attr name="textText" format="string" />
</declare-styleable>
<declare-styleable name="CH3">
<attr name="textFex" format="string" />
</declare-styleable>
</resources>
This is the control CH2.java which ia in subspackage and does not work:
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();
}
}
}
This is CH3.java which works:
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();
}
}
}
Both sources use the same category_header.xml. The layout is loaded without problem. I can use both like this:
<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>
How can I make CH2 work? Or is it impossible to use another package?
Sidequest: Can I make both controls to use the same XML attribute textText
or will they always have to use different attributes? Or can the declareable-style name be different from the components name?
Another approach with a new declare-styleable:
<declare-styleable name="controls.CH2">
<attr name="textText" format="string" />
</declare-styleable>
But it does not seem to be usable. XML view always says Unexpected text found in layout file:, regardless how I use 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>
or
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>
Upvotes: 0
Views: 1521
Reputation: 11782
I just went back to my own attribute files and there's no reference anywhere to the very deep sub-package where my layout lives... as a side note, you can have multiple elements use the same attribute if you do this in your attrs file:
<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>
My study of the android source code shows a few examples where they do exactly what you're describing, where they have a single custom attribute file pointing to view classes in different packages. The only glaring difference I saw was that the Views were declared in layout like this:
<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>
I honestly couldn't tell you why that would make a difference... but every time they need custom attributes that is the format used
Upvotes: 1