我的PreferenceScreen上的滑块

我希望我的偏好菜单有一些东西来改变振动的持续时间。

prefs.xml没有slider标签,那么最好的办法是什么?

您可以创build自己的Preference类来扩展DialogPreference并将SeekBar显示为对话框视图。

我改进了由Macarse提供的链接,以便仅在okbutton单击时保存该值,以便您可以在XML文件中使用@string/...值。

这里是代码:

 /* The following code was written by Matthew Wiggins * and is released under the APACHE 2.0 license * * http://www.apache.org/licenses/LICENSE-2.0 * * Improvements : * - save the value on positive button click, not on seekbar change * - handle @string/... values in xml file */ package fr.atcm.carpooling.views.utils; import android.app.AlertDialog; import android.content.Context; import android.os.Bundle; import android.preference.DialogPreference; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; public class SeekBarPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener, OnClickListener { // ------------------------------------------------------------------------------------------ // Private attributes : private static final String androidns="http://schemas.android.com/apk/res/android"; private SeekBar mSeekBar; private TextView mSplashText,mValueText; private Context mContext; private String mDialogMessage, mSuffix; private int mDefault, mMax, mValue = 0; // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // Constructor : public SeekBarPreference(Context context, AttributeSet attrs) { super(context,attrs); mContext = context; // Get string value for dialogMessage : int mDialogMessageId = attrs.getAttributeResourceValue(androidns, "dialogMessage", 0); if(mDialogMessageId == 0) mDialogMessage = attrs.getAttributeValue(androidns, "dialogMessage"); else mDialogMessage = mContext.getString(mDialogMessageId); // Get string value for suffix (text attribute in xml file) : int mSuffixId = attrs.getAttributeResourceValue(androidns, "text", 0); if(mSuffixId == 0) mSuffix = attrs.getAttributeValue(androidns, "text"); else mSuffix = mContext.getString(mSuffixId); // Get default and max seekbar values : mDefault = attrs.getAttributeIntValue(androidns, "defaultValue", 0); mMax = attrs.getAttributeIntValue(androidns, "max", 100); } // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // DialogPreference methods : @Override protected View onCreateDialogView() { LinearLayout.LayoutParams params; LinearLayout layout = new LinearLayout(mContext); layout.setOrientation(LinearLayout.VERTICAL); layout.setPadding(6,6,6,6); mSplashText = new TextView(mContext); mSplashText.setPadding(30, 10, 30, 10); if (mDialogMessage != null) mSplashText.setText(mDialogMessage); layout.addView(mSplashText); mValueText = new TextView(mContext); mValueText.setGravity(Gravity.CENTER_HORIZONTAL); mValueText.setTextSize(32); params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); layout.addView(mValueText, params); mSeekBar = new SeekBar(mContext); mSeekBar.setOnSeekBarChangeListener(this); layout.addView(mSeekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); if (shouldPersist()) mValue = getPersistedInt(mDefault); mSeekBar.setMax(mMax); mSeekBar.setProgress(mValue); return layout; } @Override protected void onBindDialogView(View v) { super.onBindDialogView(v); mSeekBar.setMax(mMax); mSeekBar.setProgress(mValue); } @Override protected void onSetInitialValue(boolean restore, Object defaultValue) { super.onSetInitialValue(restore, defaultValue); if (restore) mValue = shouldPersist() ? getPersistedInt(mDefault) : 0; else mValue = (Integer)defaultValue; } // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // OnSeekBarChangeListener methods : @Override public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) { String t = String.valueOf(value); mValueText.setText(mSuffix == null ? t : t.concat(" " + mSuffix)); } @Override public void onStartTrackingTouch(SeekBar seek) {} @Override public void onStopTrackingTouch(SeekBar seek) {} public void setMax(int max) { mMax = max; } public int getMax() { return mMax; } public void setProgress(int progress) { mValue = progress; if (mSeekBar != null) mSeekBar.setProgress(progress); } public int getProgress() { return mValue; } // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // Set the positive button listener and onClick action : @Override public void showDialog(Bundle state) { super.showDialog(state); Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE); positiveButton.setOnClickListener(this); } @Override public void onClick(View v) { if (shouldPersist()) { mValue = mSeekBar.getProgress(); persistInt(mSeekBar.getProgress()); callChangeListener(Integer.valueOf(mSeekBar.getProgress())); } ((AlertDialog) getDialog()).dismiss(); } // ------------------------------------------------------------------------------------------ } 

编辑:

这是一个截图:

SeekBarPreference截图

编辑:在arlomedia的需求,这里是所有需要的代码片段(我刚刚重新创build一个新的projet,它是完美的工作,我纠正了SeekBarPreference类的一些错误,所以不要忘记重新复制/粘贴它):

主要活动 :

 package fr.at.testsliderpref; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { switch(item.getItemId()) { case R.id.menu_settings : { startActivity(new Intent(this, SettingsActivity.class)); break; } } return true; } } 

SettingsActivity:

 package fr.at.testsliderpref; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import fr.at.testsliderpref.utils.SeekBarPreference; public class SettingsActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { // Call super : super.onCreate(savedInstanceState); // Set the activity's fragment : getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); } public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener { private SeekBarPreference _seekBarPref; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.activity_settings); // Get widgets : _seekBarPref = (SeekBarPreference) this.findPreference("SEEKBAR_VALUE"); // Set listener : getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); // Set seekbar summary : int radius = PreferenceManager.getDefaultSharedPreferences(this.getActivity()).getInt("SEEKBAR_VALUE", 50); _seekBarPref.setSummary(this.getString(R.string.settings_summary).replace("$1", ""+radius)); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { // Set seekbar summary : int radius = PreferenceManager.getDefaultSharedPreferences(this.getActivity()).getInt("SEEKBAR_VALUE", 50); _seekBarPref.setSummary(this.getString(R.string.settings_summary).replace("$1", ""+radius)); } } } 

layout> activity_main.xml:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/textview_text" /> </RelativeLayout> 

菜单> main.xml:

 <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_settings" android:title="@string/menu_settings" android:icon="@android:drawable/ic_menu_preferences"/> </menu> 

xml> activity_settings.xml:

 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <fr.at.testsliderpref.utils.SeekBarPreference android:defaultValue="50" android:dialogMessage="@string/settings_dialog_message" android:key="SEEKBAR_VALUE" android:max="100" android:summary="@string/settings_summary" android:text="@string/settings_unit" android:title="@string/settings_title" /> </PreferenceScreen> 

values> strings.xml:

 <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">TestSliderPref</string> <string name="textview_text">SeekBarPreference test</string> <string name="menu_settings">Settings</string> <string name="settings_dialog_message">Here comes a message</string> <string name="settings_summary">Current value is $1</string> <string name="settings_unit">Km</string> <string name="settings_title">Here comes the title</string> </resources> 

不要忘记将您的SettingsActivity添加到清单,它应该是确定的。

实现这个目的的一个简单方法是为您的preferences.xml添加一个空的首选项,该首选项使用包含seekbar的布局。

在你的preferences.xml中添加

 <Preference android:layout="@layout/sliderlayout" /> 

在布局下添加sliderlayout

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <SeekBar android:id="@+id/seekBar1" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> 

这是很好的滑块偏好组件 – Android Slider偏好库 在这里输入图像说明

https://github.com/jayschwa/AndroidSliderPreference

Tim对答案中提供的代码做了一点改进。 这只需在用户移动滑块时对输出值进行实时调整,而不是要求用户单击“确定”button才能进行更改。

这对于像音乐音量滑块这样的东西很有用,用户应该能够听到音量调节。

如果用户点击“确定”,则保持新的值。 如果用户点击“取消”,则恢复原来的预调值。

感谢和信贷应该去蒂姆,我只是增加了额外的onClick监听器,并将值更新到onChange监听器。

 package fr.atcm.carpooling.views.utils; /* The following code was written by Matthew Wiggins * and is released under the APACHE 2.0 license * * http://www.apache.org/licenses/LICENSE-2.0 * * Improvements : * - save the value on positive button click and/or seekbar change * - restore pre-adjustment value on negative button click */ import android.R; import android.app.AlertDialog; import android.content.Context; import android.os.Bundle; import android.preference.DialogPreference; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; public class SeekBarPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener, OnClickListener { // ------------------------------------------------------------------------------------------ // Private attributes : private static final String androidns = "http://schemas.android.com/apk/res/android"; private SeekBar mSeekBar; private TextView mSplashText, mValueText; private Context mContext; private String mDialogMessage, mSuffix; private int mDefault, mMax, mValue, mOrig = 0; // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // Constructor : public SeekBarPreference(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; // Get string value for dialogMessage : int mDialogMessageId = attrs.getAttributeResourceValue(androidns, "dialogMessage", 0); if (mDialogMessageId == 0) mDialogMessage = attrs .getAttributeValue(androidns, "dialogMessage"); else mDialogMessage = mContext.getString(mDialogMessageId); // Get string value for suffix (text attribute in xml file) : int mSuffixId = attrs.getAttributeResourceValue(androidns, "text", 0); if (mSuffixId == 0) mSuffix = attrs.getAttributeValue(androidns, "text"); else mSuffix = mContext.getString(mSuffixId); // Get default and max seekbar values : mDefault = attrs.getAttributeIntValue(androidns, "defaultValue", 0); mMax = attrs.getAttributeIntValue(androidns, "max", 100); } // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // DialogPreference methods : @Override protected View onCreateDialogView() { LinearLayout.LayoutParams params; LinearLayout layout = new LinearLayout(mContext); layout.setOrientation(LinearLayout.VERTICAL); layout.setPadding(6, 6, 6, 6); mSplashText = new TextView(mContext); mSplashText.setPadding(30, 10, 30, 10); if (mDialogMessage != null) mSplashText.setText(mDialogMessage); layout.addView(mSplashText); mValueText = new TextView(mContext); mValueText.setGravity(Gravity.CENTER_HORIZONTAL); mValueText.setTextSize(32); params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); layout.addView(mValueText, params); mSeekBar = new SeekBar(mContext); mSeekBar.setOnSeekBarChangeListener(this); layout.addView(mSeekBar, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); if (shouldPersist()) mValue = getPersistedInt(mDefault); mSeekBar.setMax(mMax); mSeekBar.setProgress(mValue); return layout; } @Override protected void onBindDialogView(View v) { super.onBindDialogView(v); mSeekBar.setMax(mMax); mSeekBar.setProgress(mValue); } @Override protected void onSetInitialValue(boolean restore, Object defaultValue) { super.onSetInitialValue(restore, defaultValue); // Set adjustable value if (restore) mValue = shouldPersist() ? getPersistedInt(mDefault) : 0; else mValue = (Integer) defaultValue; // Set original pre-adjustment value mOrig = mValue; } // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // OnSeekBarChangeListener methods : @Override public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) { String t = String.valueOf(value); mValueText.setText(mSuffix == null ? t : t.concat(" " + mSuffix)); if (shouldPersist()) { mValue = mSeekBar.getProgress(); persistInt(mSeekBar.getProgress()); callChangeListener(Integer.valueOf(mSeekBar.getProgress())); } } @Override public void onStartTrackingTouch(SeekBar seek) { } @Override public void onStopTrackingTouch(SeekBar seek) { } public void setMax(int max) { mMax = max; } public int getMax() { return mMax; } public void setProgress(int progress) { mValue = progress; if (mSeekBar != null) mSeekBar.setProgress(progress); } public int getProgress() { return mValue; } // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // Set the positive button listener and onClick action : @Override public void showDialog(Bundle state) { super.showDialog(state); Button positiveButton = ((AlertDialog) getDialog()) .getButton(AlertDialog.BUTTON_POSITIVE); Button negativeButton = ((AlertDialog) getDialog()) .getButton(AlertDialog.BUTTON_NEGATIVE); positiveButton.setOnClickListener(cListenPos); negativeButton.setOnClickListener(cListenNeg); } View.OnClickListener cListenPos = new View.OnClickListener() { public void onClick(View v) { if (shouldPersist()) { mValue = mSeekBar.getProgress(); mOrig = mSeekBar.getProgress(); persistInt(mSeekBar.getProgress()); callChangeListener(Integer.valueOf(mSeekBar.getProgress())); } ((AlertDialog) getDialog()).dismiss(); } }; View.OnClickListener cListenNeg = new View.OnClickListener() { public void onClick(View v) { if (shouldPersist()) { mValue = mOrig; persistInt(mOrig); callChangeListener(Integer.valueOf(mOrig)); } ((AlertDialog) getDialog()).dismiss(); } }; @Override public void onClick(View v) {} // ------------------------------------------------------------------------------------------ } 

还有一个这样的实现。 所有的信贷都是Tim Autin。

我想要显示从XML数组加载的值

看起来像这样

Seekbar设置从XML加载项目

代码 – 这现在扩展ListPreference

 import android.app.AlertDialog; import android.content.Context; import android.os.Bundle; import android.preference.ListPreference; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; public class SeekBarListPreference extends ListPreference implements SeekBar.OnSeekBarChangeListener, View.OnClickListener { // ------------------------------------------------------------------------------------------ // Private attributes : private static final String androidns = "http://schemas.android.com/apk/res/android"; private SeekBar mSeekBar; private TextView mSplashText, mValueText; private Context mContext; private String mDialogMessage; // ------------------------------------------------------------------------------------------ public SeekBarListPreference(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; // Get string value for dialogMessage : int mDialogMessageId = attrs.getAttributeResourceValue(androidns, "dialogMessage", 0); if (mDialogMessageId == 0) mDialogMessage = attrs.getAttributeValue(androidns, "dialogMessage"); else mDialogMessage = mContext.getString(mDialogMessageId); } // ------------------------------------------------------------------------------------------ // DialogPreference methods : @Override protected View onCreateDialogView() { LinearLayout.LayoutParams params; LinearLayout layout = new LinearLayout(mContext); layout.setOrientation(LinearLayout.VERTICAL); layout.setPadding(6, 6, 6, 6); mSplashText = new TextView(mContext); mSplashText.setPadding(30, 10, 30, 10); if (mDialogMessage != null) mSplashText.setText(mDialogMessage); layout.addView(mSplashText); mValueText = new TextView(mContext); mValueText.setGravity(Gravity.CENTER_HORIZONTAL); mValueText.setTextSize(32); params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); layout.addView(mValueText, params); mSeekBar = new SeekBar(mContext); mSeekBar.setOnSeekBarChangeListener(this); layout.addView(mSeekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); setProgressBarValue(); return layout; } @Override protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { // do not call super } private void setProgressBarValue() { String mValue = null; if (shouldPersist()) { mValue = getValue(); } final int max = this.getEntries().length - 1; mSeekBar.setMax(max); mSeekBar.setProgress(this.findIndexOfValue(mValue)); } @Override protected void onBindDialogView(View v) { super.onBindDialogView(v); setProgressBarValue(); } @Override public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) { final CharSequence textToDisplay = getEntryFromValue(value); mValueText.setText(textToDisplay); } private CharSequence getEntryFromValue(int value) { CharSequence[] entries = getEntries(); return value >= 0 && entries != null ? entries[value] : null; } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void showDialog(Bundle state) { super.showDialog(state); Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE); positiveButton.setOnClickListener(this); } @Override public void onClick(View v) { if (shouldPersist()) { final int progressChoice = mSeekBar.getProgress(); setValueIndex(progressChoice); } getDialog().dismiss(); } } 

现在在首选项文件中的用法

 <com.yourfullpackage.SeekBarListPreference android:defaultValue="0" android:dialogMessage="@string/time_limit_pref" android:entries="@array/timeListArray" android:entryValues="@array/timeListValues" android:key="time" android:summary="Select time limit" android:title="Time" /> 

和数组

 <string-array name="timeListArray"> <item>10 Seconds</item> <item>30 Seconds</item> <item>1 Minute</item> <item>2 Minutes</item> <item>Unlimited</item> </string-array> <!--This is going to be in seconds--> <string-array name="timeListValues"> <item>10</item> <item>30</item> <item>60</item> <item>120</item> <item>0</item> </string-array> 

作为一个奖励,如果你已经有了ListPreferences,你不需要添加任何额外的东西来显示摘要作为当前值。 所以这工作得很好

  @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { SetSummaryForPreferenceKey(key); } private void SetSummaryForPreferenceKey(String key) { Preference preference = findPreference(key); // This works with our new SeekBarPreference if (preference instanceof ListPreference) { ListPreference listPref = (ListPreference) preference; listPref.setSummary(listPref.getEntry()); } } 

Tim的回答及其派生的一小改进:

 protected void onBindDialogView(View v) { super.onBindDialogView(v); mSeekBar.setMax(mMax); mSeekBar.setProgress(mValue); String t = String.valueOf(mValue); mValueText.setText(mSuffix == null ? t : t.concat(" " + mSuffix)); } 

它将在开始时填充当前的值,否则为空,直到您实际滑动滑块。