versiones pie oreo developer descargar android

android - pie - Control deslizante en mi pantalla de preferencia



android pie (7)

Quiero que mi menú de preferencias tenga algo para cambiar la duración de una vibración.

No hay una etiqueta slider para prefs.xml, entonces, ¿cuál es la mejor manera de hacer esto?



He hecho una leve mejora en el código proporcionado en la respuesta de Tim. Esto simplemente hace ajustes en vivo al valor de salida cuando el usuario mueve el control deslizante, en lugar de requerir que el usuario haga clic en el botón "Aceptar" para que se realicen los cambios.

Esto es útil para cosas como un control deslizante de volumen de música, donde el usuario debería poder escuchar el ajuste de volumen a medida que se realiza.

Si el usuario hace clic en "Aceptar", el nuevo valor se mantiene. Si el usuario hace clic en "Cancelar", se restaura el valor original de ajuste previo.

Las gracias y el crédito deben ir a Tim, acabo de agregar el oyente onClick adicional y puse la actualización de valor en el oyente 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) {} // ------------------------------------------------------------------------------------------ }


Mejoré el enlace proporcionado por Macarse, para que el valor se guarde solo al hacer clic en el botón Aceptar, y para que pueda usar los valores de @string/... en el archivo XML.

Aquí está el código:

/* 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(); } // ------------------------------------------------------------------------------------------ }

EDITAR:

Aquí hay una captura de pantalla :

EDITAR: a petición de arlomedia, aquí están todas las piezas de código necesarias (acabo de recrear un nuevo proyecto, está funcionando perfectamente. Corrigí algunos errores en la clase SeekBarPreference, así que no olvide volver a copiarlo / pegarlo):

Actividad principal :

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; } }

ConfiguraciónActividad:

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>

menú> 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>

valores> cadenas.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>

No se olvide de agregar su SettingsActivity al manifiesto, y debería estar bien.


Podría crear su propia clase de Preferencia que amplíe DialogPreference y muestre un SeekBar como la vista de diálogo.


Una forma fácil de lograr esto es agregar una preferencia vacía a su preferences.xml que usa un diseño que incluye una barra de búsqueda.

En sus preferences.xml agregue

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

debajo de los diseños agrega el 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>


Una implementación más de esto. Todo el crédito va a Tim Autin.

Quería tener los valores mostrados cargados desde matrices XML

Se parece a esto

Código - esto ahora extiende 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(); } }

El uso en el archivo de preferencias es ahora

<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" />

Y las matrices

<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>

Como beneficio adicional si ya tiene ListPreferences, no necesita agregar nada extra para mostrar el resumen como el valor actual. Así que esto funciona bien

@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()); } }


Una pequeña mejora de la respuesta de Tim y sus derivados:

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)); }

Rellenará el valor actual al inicio, que de lo contrario está vacío hasta que realmente deslice el control deslizante.