如何基于布局创建 XML 友好的控件?
How do you create an XML-friendly control based on a layout?
我创建了一个自定义控件,它是 LinearLayout 的子class。我还创建了此控件所基于的布局文件。最后我定义了属性,我在构造函数中解析这些属性以设置我的自定义属性。例如,其中一个属性称为 'text'.
这是我的代码的简化版本(我去掉了很多其他属性等,所以我们可以只关注一个 属性 'text'):
首先,class(我们自定义的 RadioButton 版本)...
public class RadioButton extends LinearLayout
{
private TextView textView;
public RadioButton(Context context, AttributeSet attrs)
{
super(context, attrs);
initAttributes(attrs, 0);
}
private void initAttributes(AttributeSet attrs, int defStyle)
{
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CheckBoxView, defStyle, 0);
text = a.getString(R.styleable.RadioButton_text);
if(text == null)
text = "Not set";
a.recycle();
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
textView = (TextView)findViewById(R.id.textView);
textView.setText(text);
}
private String text;
public String getText() { return text; }
public void setText(String newValue)
{
text = newValue;
if(textView != null)
textView.setText(text);
}
}
这是 attrs.xml 文件...
<resources>
<attr name="text" format="string" />
<declare-styleable name="RadioButton">
<attr name="text" />
</declare-styleable>
</resources>
这里是 'reusable_radiobutton.xml' 布局文件(注意:内部 RadioButtonView 是自定义呈现的视图并且工作正常):
<?xml version="1.0" encoding="utf-8"?>
<com.somedomain.reusable.ui.RadioButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<com.somedomain.reusable.ui.RadioButtonView
android:id="@+id/radioButtonView"
style="@style/DefaultRadioButtonView" />
<TextView
android:id="@+id/textView"
style="@style/DefaultRadioButtonText" />
</com.somedomain.reusable.ui.RadioButton>
有了上面的内容,我的控件的用户可以简单地将它包含在他们自己的布局文件中,就像这样...
<include android:id="@+id/someRadioButton"
layout="@layout/reusable_radiobutton" />
在他们的代码中,使用以下内容,他们可以获得该实例并按照他们的意愿使用它,就像这样...
RadioButton someRadioButton = (RadioButton)findViewById(R.id.someRadioButton);
someRadioButton.text = "Woot!";
这按预期工作。
然而,这并不...
<include android:id="@+id/someRadioButton"
layout="@layout/reusable_radiobutton"
app:text="Hello World!" />
它给了我一个警告,但忽略了它。
然后我尝试了这个...
<com.somedomain.reusable.ui.RadioButton
app:text="Hello World!" />
虽然这确实实例化了我的控件并确实通过属性将 'Hello World!' 传递给了我的 属性,但实际上没有加载任何内容,甚至没有将布局文件关联到我的 class,因此没有任何内容出现在屏幕!
那么我如何基于布局创建自定义视图,其他开发人员可以简单地在他们自己的布局文件中引用它,同时还允许他们设置自定义属性?
希望一切都说得通! :)
Note: The Android documentation talks about exactly what I'm after, 'Compound Controls' as referenced here, but they don't give an example of using a layout to define the compounded control. However, I feel that was pretty close.
在 SO 上 here 找到它。我没有意识到你可以给自己充气。那并使用 Merge 标签为我处理了它。
我创建了一个自定义控件,它是 LinearLayout 的子class。我还创建了此控件所基于的布局文件。最后我定义了属性,我在构造函数中解析这些属性以设置我的自定义属性。例如,其中一个属性称为 'text'.
这是我的代码的简化版本(我去掉了很多其他属性等,所以我们可以只关注一个 属性 'text'):
首先,class(我们自定义的 RadioButton 版本)...
public class RadioButton extends LinearLayout
{
private TextView textView;
public RadioButton(Context context, AttributeSet attrs)
{
super(context, attrs);
initAttributes(attrs, 0);
}
private void initAttributes(AttributeSet attrs, int defStyle)
{
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CheckBoxView, defStyle, 0);
text = a.getString(R.styleable.RadioButton_text);
if(text == null)
text = "Not set";
a.recycle();
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
textView = (TextView)findViewById(R.id.textView);
textView.setText(text);
}
private String text;
public String getText() { return text; }
public void setText(String newValue)
{
text = newValue;
if(textView != null)
textView.setText(text);
}
}
这是 attrs.xml 文件...
<resources>
<attr name="text" format="string" />
<declare-styleable name="RadioButton">
<attr name="text" />
</declare-styleable>
</resources>
这里是 'reusable_radiobutton.xml' 布局文件(注意:内部 RadioButtonView 是自定义呈现的视图并且工作正常):
<?xml version="1.0" encoding="utf-8"?>
<com.somedomain.reusable.ui.RadioButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<com.somedomain.reusable.ui.RadioButtonView
android:id="@+id/radioButtonView"
style="@style/DefaultRadioButtonView" />
<TextView
android:id="@+id/textView"
style="@style/DefaultRadioButtonText" />
</com.somedomain.reusable.ui.RadioButton>
有了上面的内容,我的控件的用户可以简单地将它包含在他们自己的布局文件中,就像这样...
<include android:id="@+id/someRadioButton"
layout="@layout/reusable_radiobutton" />
在他们的代码中,使用以下内容,他们可以获得该实例并按照他们的意愿使用它,就像这样...
RadioButton someRadioButton = (RadioButton)findViewById(R.id.someRadioButton);
someRadioButton.text = "Woot!";
这按预期工作。
然而,这并不...
<include android:id="@+id/someRadioButton"
layout="@layout/reusable_radiobutton"
app:text="Hello World!" />
它给了我一个警告,但忽略了它。
然后我尝试了这个...
<com.somedomain.reusable.ui.RadioButton
app:text="Hello World!" />
虽然这确实实例化了我的控件并确实通过属性将 'Hello World!' 传递给了我的 属性,但实际上没有加载任何内容,甚至没有将布局文件关联到我的 class,因此没有任何内容出现在屏幕!
那么我如何基于布局创建自定义视图,其他开发人员可以简单地在他们自己的布局文件中引用它,同时还允许他们设置自定义属性?
希望一切都说得通! :)
Note: The Android documentation talks about exactly what I'm after, 'Compound Controls' as referenced here, but they don't give an example of using a layout to define the compounded control. However, I feel that was pretty close.
在 SO 上 here 找到它。我没有意识到你可以给自己充气。那并使用 Merge 标签为我处理了它。