Android: 如何在自定义首选项属性 中使用xml 文件中的字符串资源?
Android: How to use string resource from xml file in property of customized preference?
我已经使用此站点实现了自定义搜索栏首选项 - seekbar preference 并且工作正常。现在我想从 string.xml
文件中向搜索栏的自定义属性添加值,而不是对它们进行硬编码:
而不是写 customseekbar:unitsRight="Seconds"
我想要一个像 <string name="units">Seconds</string>
这样的字符串资源并像这样使用它:customseekbar:unitsRight="@string/units"
。我已经尝试实现这个 guide。我的相关代码是:
attrs.xml
<resources>
<declare-styleable name="CustomSeekBarPreference">
<attr name="unitsRight" format="reference|string"/>
</declare-styleable>
和构造函数 -
CustomSeekBarPreference.java
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
private static final String APPLICATIONNS="http://CustomSeekBarPreference.com";
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CustomSeekBarPreference, 0 ,0);
mUnitsRight = a.getString(R.styleable.CustomSeekBarPreference_unitsRight);
a.recycle();
}
和布局 -
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:customseekbar="http://CustomSeekBarPreference.com" >
<com.x.sharedpreferencestestapp.CustomSeekBarPreference
android:key="1"
android:defaultValue="30"
android:max="100"
customseekbar:min="0"
android:title="Default step"
customseekbar:unitsRight="@string/units"/>
</PreferenceScreen>
但是如您所见,我得到的是 'null' 而不是正确的值:
即使我将值更改为固定字符串而不是字符串资源,如 customseekbar:unitsRight="Seconds"
我仍然得到相同的结果。只是为了说清楚 - 如果我坚持搜索栏首选项的原始代码:mUnitsRight = getAttributeStringValue(attrs, APPLICATIONNS, "unitsRight", "defaultValue")
它有效,但不适用于字符串资源。
由于您在布局中为其声明的命名空间,您将获得该属性值的 null XML - http://CustomSeekBarPreference.com
.
据我所知,obtainStyledAttributes()
方法只能提取标准 Android 资源命名空间 – http://schemas.android.com/apk/res/android
– 或您应用程序的资源命名空间中的属性,是 http://schemas.android.com/apk/res/
加上应用程序的包名称。任何其他命名空间中的属性都将被忽略,并且不会出现在返回的 TypedArray
中,这就是为什么无论值是硬编码字符串还是资源引用都会得到 null 的原因。
在您所关注的示例中,他们使用了类似的非标准命名空间,但他们直接从 AttributeSet
中提取值,并在 getAttributeValue()
中指定该命名空间就此打电话。我不能说我见过这种经常以这种方式使用的特定方法,我能看到的唯一好处是它使您不必定义自己的自定义属性,这是一项相当微不足道的任务。
有几种方法可以解决这个问题。
将这些布局属性移动到应用的命名空间中,并为每个属性定义一个 attr
资源。
这是您链接的开发人员页面中演示的方法,可能是实现自定义 View
属性的最常见和最熟悉的方法。
首先将布局中的命名空间声明更改为:
xmlns:customseekbar="http://schemas.android.com/apk/res-auto"
(res-auto
段是一种便利,它将导致实际的命名空间名称与当前包名称适当地构造,如前所述。)
使用您发布的设置,这将导致 customseekbar:min
错误,因为您没有在您的应用中将 min
定义为属性资源 (attr
)。您可以简单地定义 attr
,然后像处理 unitsRight
一样处理它;即,从 obtainStyledAttributes()
返回的 TypedArray
中检索它的值。您可以对可能需要的任何其他自定义属性执行相同的操作。
修改 CustomSeekBarPreference
示例中的 getAttributeStringValue()
方法以处理资源引用。
就修改给定示例而言,这可能是更简单的选项,但直接访问 AttributeSet
值会阻止这些值针对您可能希望应用的任何主题或样式进行调整。如果这不是问题,那么必要的更改就相当简单了。
在修改后的方法中,我们只需要先检查属性值是否为资源值,使用AttributeSet#getAttributeResourceValue()
。如果该方法 returns 是一个有效的标识符,我们将使用 Resources#getString()
检索实际值。如果不是,我们将属性值视为纯字符串。
private String getAttributeStringValue(AttributeSet attrs, String namespace,
String name, String defaultValue) {
String value = null;
int resId = attrs.getAttributeResourceValue(namespace, name, 0);
if (resId == 0) {
value = attrs.getAttributeValue(namespace, name);
if (value == null)
value = defaultValue;
}
else {
value = getContext().getResources().getString(resId);
}
return value;
}
使用此方法,您无需定义自定义属性,并且布局命名空间可以保留在发布的代码段中。
我已经使用此站点实现了自定义搜索栏首选项 - seekbar preference 并且工作正常。现在我想从 string.xml
文件中向搜索栏的自定义属性添加值,而不是对它们进行硬编码:
而不是写 customseekbar:unitsRight="Seconds"
我想要一个像 <string name="units">Seconds</string>
这样的字符串资源并像这样使用它:customseekbar:unitsRight="@string/units"
。我已经尝试实现这个 guide。我的相关代码是:
attrs.xml
<resources>
<declare-styleable name="CustomSeekBarPreference">
<attr name="unitsRight" format="reference|string"/>
</declare-styleable>
和构造函数 -
CustomSeekBarPreference.java
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
private static final String APPLICATIONNS="http://CustomSeekBarPreference.com";
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CustomSeekBarPreference, 0 ,0);
mUnitsRight = a.getString(R.styleable.CustomSeekBarPreference_unitsRight);
a.recycle();
}
和布局 -
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:customseekbar="http://CustomSeekBarPreference.com" >
<com.x.sharedpreferencestestapp.CustomSeekBarPreference
android:key="1"
android:defaultValue="30"
android:max="100"
customseekbar:min="0"
android:title="Default step"
customseekbar:unitsRight="@string/units"/>
</PreferenceScreen>
但是如您所见,我得到的是 'null' 而不是正确的值:customseekbar:unitsRight="Seconds"
我仍然得到相同的结果。只是为了说清楚 - 如果我坚持搜索栏首选项的原始代码:mUnitsRight = getAttributeStringValue(attrs, APPLICATIONNS, "unitsRight", "defaultValue")
它有效,但不适用于字符串资源。
由于您在布局中为其声明的命名空间,您将获得该属性值的 null XML - http://CustomSeekBarPreference.com
.
据我所知,obtainStyledAttributes()
方法只能提取标准 Android 资源命名空间 – http://schemas.android.com/apk/res/android
– 或您应用程序的资源命名空间中的属性,是 http://schemas.android.com/apk/res/
加上应用程序的包名称。任何其他命名空间中的属性都将被忽略,并且不会出现在返回的 TypedArray
中,这就是为什么无论值是硬编码字符串还是资源引用都会得到 null 的原因。
在您所关注的示例中,他们使用了类似的非标准命名空间,但他们直接从 AttributeSet
中提取值,并在 getAttributeValue()
中指定该命名空间就此打电话。我不能说我见过这种经常以这种方式使用的特定方法,我能看到的唯一好处是它使您不必定义自己的自定义属性,这是一项相当微不足道的任务。
有几种方法可以解决这个问题。
将这些布局属性移动到应用的命名空间中,并为每个属性定义一个
attr
资源。这是您链接的开发人员页面中演示的方法,可能是实现自定义
View
属性的最常见和最熟悉的方法。首先将布局中的命名空间声明更改为:
xmlns:customseekbar="http://schemas.android.com/apk/res-auto"
(
res-auto
段是一种便利,它将导致实际的命名空间名称与当前包名称适当地构造,如前所述。)使用您发布的设置,这将导致
customseekbar:min
错误,因为您没有在您的应用中将min
定义为属性资源 (attr
)。您可以简单地定义attr
,然后像处理unitsRight
一样处理它;即,从obtainStyledAttributes()
返回的TypedArray
中检索它的值。您可以对可能需要的任何其他自定义属性执行相同的操作。
修改
CustomSeekBarPreference
示例中的getAttributeStringValue()
方法以处理资源引用。就修改给定示例而言,这可能是更简单的选项,但直接访问
AttributeSet
值会阻止这些值针对您可能希望应用的任何主题或样式进行调整。如果这不是问题,那么必要的更改就相当简单了。在修改后的方法中,我们只需要先检查属性值是否为资源值,使用
AttributeSet#getAttributeResourceValue()
。如果该方法 returns 是一个有效的标识符,我们将使用Resources#getString()
检索实际值。如果不是,我们将属性值视为纯字符串。private String getAttributeStringValue(AttributeSet attrs, String namespace, String name, String defaultValue) { String value = null; int resId = attrs.getAttributeResourceValue(namespace, name, 0); if (resId == 0) { value = attrs.getAttributeValue(namespace, name); if (value == null) value = defaultValue; } else { value = getContext().getResources().getString(resId); } return value; }
使用此方法,您无需定义自定义属性,并且布局命名空间可以保留在发布的代码段中。