65.9K
CodeProject 正在变化。 阅读更多。
Home

SeekBar 首选项

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (10投票s)

2011年3月1日

CPOL

3分钟阅读

viewsIcon

91780

downloadIcon

3113

如何使用 SeekBar 构建首选项小部件。

引言

在本文中,我将尝试展示如何创建自己的带有 SeekBar 的偏好设置小部件。

seekbarpreferencedialog.png

背景

Android 提供了一些方便的小部件,例如 CheckBoxPreferenceEditTextPreferenceListPreference 来构建漂亮的偏好设置屏幕。但是,如果现有的小部件不能满足您的要求,您可以轻松地基于现有的小部件创建自己的小部件。

通常,一些整数偏好设置具有有意义的限制,例如音量或亮度级别。在这种情况下,构建您自己的小部件来管理这些偏好设置,然后在应用程序中重复使用该小部件是有意义的。

准备工作

DialogPreference 是此类小部件的最佳超类。它提供了一个偏好设置,该偏好设置在偏好设置列表中显示两行文本(标题和摘要),并在单击时显示带有“确定”/“取消”按钮的对话框。

seekbarpreference.png

我们称它为 SeekBarPreference。此小部件的参数可以是最小值、最大值和当前默认值。实际的当前值将通过给定的键存储在关联的共享偏好设置中。

在这种情况下,文件 /res/xml/preferences.xml 可能看起来像这样

<PreferenceScreen 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:example="http://schemas.android.com/apk/res/com.mnm.seekbarpreference">
    
    <com.mnm.seekbarpreference.SeekBarPreference
        android:key="seekBarPreference"
	android:title="@string/dialog_title"
	android:dialogTitle="@string/dialog_title"
	android:summary="@string/summary"
	android:persistent="true"
	android:defaultValue="20"
	example:minValue="10"
	example:maxValue="50" />
    
</PreferenceScreen>

现有标签可用于设置默认当前值。但是最小值和最大值需要它们自己的标签。为此,/res/values/attrs.xml 文件应使用以下声明进行扩展

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="com.mnm.seekbarpreference.SeekBarPreference">
        <attr name="minValue" format="integer" />
        <attr name="maxValue" format="integer" />
    </declare-styleable>
</resources>

<declare-styleable> 标签的 Name 属性应包含限定的小部件类名。

preferences.xml 中应以更完整的格式(http://schemas.android.com/apk/res/qualified_class_name)定义相同的名称,作为附加的命名空间(见上文)。

使用 XML 的最后阶段是为在小部件单击时启动的对话框创建布局。这是一个非常常见的代码,可以省略而不会产生任何影响。只需提到它包含最小值、最大值和当前值的 TextViews 以及 SeekBar

现在,我们可以继续实现 SeekBarPreference 类。

实现

首先,所有提到的属性都应在小部件构造函数中读取

mMinValue = attrs.getAttributeIntValue
	(PREFERENCE_NS, ATTR_MIN_VALUE, DEFAULT_MIN_VALUE);
mMaxValue = attrs.getAttributeIntValue
	(PREFERENCE_NS, ATTR_MAX_VALUE, DEFAULT_MAX_VALUE);
mDefaultValue = attrs.getAttributeIntValue
		(ANDROID_NS, ATTR_DEFAULT_VALUE, DEFAULT_CURRENT_VALUE);

其中常量是命名空间、属性和属性值的默认值(如果在偏好设置声明中省略它们)。

private static final String PREFERENCE_NS = 
"http://schemas.android.com/apk/res/com.mnm.seekbarpreference";
private static final String ANDROID_NS = "http://schemas.android.com/apk/res/android";

private static final String ATTR_DEFAULT_VALUE = "defaultValue";
private static final String ATTR_MIN_VALUE = "minValue";
private static final String ATTR_MAX_VALUE = "maxValue";

对于对话框设置,应重写 onCreateDialogView 方法

@Override
protected View onCreateDialogView() {

    // Get current value from settings
    mCurrentValue = getPersistedInt(mDefaultValue);

    // Inflate layout
    LayoutInflater inflater = 
	(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.dialog_slider, null);

    // Put minimum and maximum
    ((TextView) view.findViewById(R.id.min_value)).setText(Integer.toString(mMinValue));
    ((TextView) view.findViewById(R.id.max_value)).setText(Integer.toString(mMaxValue));

    // Setup SeekBar
    mSeekBar = (SeekBar) view.findViewById(R.id.seek_bar);
    mSeekBar.setMax(mMaxValue - mMinValue);
    mSeekBar.setProgress(mCurrentValue - mMinValue);
    mSeekBar.setOnSeekBarChangeListener(this);

    // Put current value
    mValueText = (TextView) view.findViewById(R.id.current_value);
    mValueText.setText(Integer.toString(mCurrentValue));

    return view;
}

当前值是通过 preferences.xml 中为特定小部件实例声明的键获取的。此外,在 SeekBar 设置期间,应考虑到它的最小值是零。这就是为什么当偏好设置的最小值与零不同时使用减法的原因。顺便说一句,此代码仅适用于非负数,并且当最大值确实大于最小值时才是正确的。

完成上一步后,可以启动应用程序,用户可以拖动拇指,但当前值标签上的文本不会更改,因为应该引入位置更改处理程序。

为此,SeekBarPreference 应该实现 OnSeekBarChangeListener 接口。在前面的代码中,正是这个接口通过“mSeekBar.setOnSeekBarChangeListener(this);”调用传递给 SeekBar。应该只实现三种可能的方法中的一种

public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) {
    mCurrentValue = value + mMinValue;
    mValueText.setText(Integer.toString(mCurrentValue));
}

再次,应该使用加法,因为 SeekBar 最小值是零。

下一步是持久化更改后的值。在对话框关闭时,它会调用 onDialogClosed 方法,该方法应该被重写

@Override
protected void onDialogClosed(boolean positiveResult) {
    super.onDialogClosed(positiveResult);

    if (!positiveResult) {
        return;
    }
    if (shouldPersist()) {
        persistInt(mCurrentValue);
    }

    notifyChanged();
}

在肯定结果中,该值是持久化的,并且 shouldPersist() 检查分析根据来自 preferences.xml 的标志 android:persistent 是否有必要这样做。

最后一行是用于一个小技巧。关键是默认情况下,小部件的摘要行是 static 的,如果它应该反映当前值,则应添加以下代码

@Override
public CharSequence getSummary() {
    String summary = super.getSummary().toString();
    int value = getPersistedInt(mDefaultValue);
    return String.format(summary, value);
}

这里,在摘要请求时,原始 string 被视为一个模板,用于将当前值放入其中。它在偏好设置屏幕打开时完美运行。但是要在通过对话框更改偏好设置后获得相同的行为,应该调用 notifyChanged()

结论

实现的窗口小部件适用于各种首选项,并且优雅地扩展了现有的首选项窗口小部件集。动态摘要行方法可以在不同的首选项窗口小部件中使用。

链接

历史

  • 2011 年 3 月 1 日:初始帖子
© . All rights reserved.