I want my preference menu to have something to change the duration of a vibration.
There is no slider tag for prefs.xml, so what is the best way to do this?
I improved the link provided by Macarse, so that the value is saved only on ok button click, and so that you can use #string/... values in the XML file.
Here is the code:
/* 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();
}
// ------------------------------------------------------------------------------------------
}
EDIT :
Here is a screenshot :
EDIT : on arlomedia's demand, here are all the needed pieces of code (I just recreated a new projet, it is perfectly working. I corrected some bugs in SeekBarPreference class, so don't forget to re-copy/paste it) :
MainActivity :
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>
menu > 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>
Don't forget to add your SettingsActivity to the manifest, and it should be OK.
You could create your own Preference class that extends DialogPreference and shows a SeekBar as the dialog view.
An easy way to achieve this is to add an empty preference to your preferences.xml which uses a layout including a seekbar.
In your preferences.xml add
<Preference android:layout="#layout/sliderlayout" />
under layouts add the 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>
If you already moved to androidX you can simply use androidx.preference.SeekBarPreference. Documentation here and here
Define it in XML like this:
<SeekBarPreference
app:defaultValue="8"
app:key="COUNT_SPEED"
app:title="Fast count speed"
/>
Note: Now in Android Studio (my current version is 3.2.1) auto-suggestions doesn't work for androidx.preference.PreferenceScreen in prefs.xml, but don't worry inflating settings from xml with setPreferencesFromResource() works fine. All needed attributes names and component references you can find here.
This is good Slider Preference component - Android Slider Preference Library
https://github.com/jayschwa/AndroidSliderPreference
One more implementation of this.
All Credit goes to Tim Autin.
I wanted to have the values displayed loaded from XML Arrays
It looks like this
Code - this now extends 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();
}
}
The usage in the preferences file is now
<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"
/>
And the arrays
<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>
As a bonus if you already have ListPreferences, you don't need to add anything extra to display the summary as the current value. So this works just fine
#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());
}
}
I've made a slight improvement on the code provided in the answer by Tim. This simply makes live adjustments to the output value as the user moves the slider, rather than requiring the user to click the "Ok" button for the changes to be made.
This is useful for things like a Music Volume slider, where the user should be able to hear the adjustment in volume as it's being made.
If the user clicks "OK" the new value is maintained. If the user clicks "Cancel" then the original pre-adjustment value is restored.
Thanks and credit should go to Tim, I just added the extra onClick listener and pushed the value updating into the onChange listener.
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) {}
// ------------------------------------------------------------------------------------------
}
One small improvement of Tim's answer and its derivates:
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));
}
It will populate current value at start which is otherwise empty until you actually slide the slider.
Related
I would like to know if is possible to make the text inside the NumberPicker clickable and to behave the same when I click the white area or the text area. The reason why I try to do such a thing, is that when I have a long string in the bar it becomes really difficult to select that area. I attached my code so far.
MainActivity.java
package com.yardimobileinterns.numberpicker;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private EditText editText;
private String[] values = {"University1", "University2", "University3"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText);
editText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
editText.setMovementMethod(null);
editText.setSelection(editText.getText().length());
showDialog(editText, values);
}
});
}
public void showDialog(EditText editText, String[] values) {
EditTextDialogFragment editTextDialogFragment = EditTextDialogFragment.getNewInstance(editText,values);
editTextDialogFragment.show(getFragmentManager(), "dialog");
}
}
EditTextDialogFragment.java
package com.yardimobileinterns.numberpicker;
import android.app.DialogFragment;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.NumberPicker;
public class EditTextDialogFragment extends DialogFragment {
public static final String EDIT_TEXT = "EDIT_TEXT";
public static final String VALUES = "VALUES";
private String[] mValues;
private NumberPicker numberPicker;
private EditText mEditText;
private String selectedValue;
public EditTextDialogFragment() {
}
public static EditTextDialogFragment getNewInstance(EditText editText, String[] values) {
EditTextDialogFragment editTextDialogFragment = new EditTextDialogFragment();
Bundle bundle = new Bundle();
bundle.putStringArray(VALUES, values);
editTextDialogFragment.setEditText(editText);
editTextDialogFragment.setArguments(bundle);
return editTextDialogFragment;
}
public void setEditText(EditText editText) {
mEditText = editText;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mValues = getArguments().getStringArray(VALUES);
}
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = layoutInflater.inflate(R.layout.university_picker, viewGroup, false);
getDialog().getWindow().setGravity(Gravity.FILL_HORIZONTAL | Gravity.BOTTOM);
numberPicker = (NumberPicker) view.findViewById(R.id.numberPicker);
numberPicker.setMinValue(0);
selectedValue = (mValues.length == 0) ? "" : mValues[0];
numberPicker.setMaxValue(mValues.length - 1);
numberPicker.setDisplayedValues(mValues);
numberPicker.setWrapSelectorWheel(false);
numberPicker.setClickable(true);
numberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
selectedValue = mValues[newVal];
}
});
numberPicker.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getDialog().dismiss();
mEditText.setText(selectedValue);
}
});
return view;
}
}
university_picker.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.yardimobileinterns.numberpicker.MainActivity"
android:background="#ffffff">
<NumberPicker
android:id="#+id/numberPicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
>
</NumberPicker>
</RelativeLayout>
Here is how it looks:
Thanks!
The actual solution that I found was to emulate onClick with onTouch, in order to allow the text to be clicked. It works well now.
package com.yardimobileinterns.numberpicker;
import android.app.DialogFragment;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.NumberPicker;
public class EditTextDialogFragment extends DialogFragment {
public static final String EDIT_TEXT = "EDIT_TEXT";
public static final String VALUES = "VALUES";
private String[] mValues;
private NumberPicker numberPicker;
private EditText mEditText;
private String selectedValue;
private int lastAction = -1;
public EditTextDialogFragment() {
}
public static EditTextDialogFragment getNewInstance(EditText editText, String[] values) {
EditTextDialogFragment editTextDialogFragment = new EditTextDialogFragment();
editTextDialogFragment.setValues(values);
editTextDialogFragment.setEditText(editText);
return editTextDialogFragment;
}
public void setEditText(EditText editText) {
mEditText = editText;
}
public void setValues(String[] values) {
mValues = values;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = layoutInflater.inflate(R.layout.university_picker, viewGroup, false);
getDialog().getWindow().setGravity(Gravity.FILL_HORIZONTAL | Gravity.BOTTOM);
numberPicker = (NumberPicker) view.findViewById(R.id.numberPicker);
numberPicker.setMinValue(0);
selectedValue = (mValues.length == 0) ? "" : mValues[mValues.length / 2];
numberPicker.setMaxValue(mValues.length - 1);
numberPicker.setDisplayedValues(mValues);
numberPicker.setValue(mValues.length / 2);
numberPicker.setWrapSelectorWheel(false);
numberPicker.setClickable(true);
numberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
selectedValue = mValues[newVal];
}
});
numberPicker.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
boolean solution = false;
switch (event.getAction()) {
case (MotionEvent.ACTION_DOWN):
lastAction = MotionEvent.ACTION_DOWN;
solution = false;
break;
case (MotionEvent.ACTION_UP):
if (lastAction == MotionEvent.ACTION_DOWN) {
solution = true;
}
lastAction = MotionEvent.ACTION_UP;
break;
case (MotionEvent.ACTION_SCROLL):
lastAction = MotionEvent.ACTION_SCROLL;
solution = false;
break;
default:
lastAction = -1;
solution = false;
break;
}
if (solution) {
getDialog().dismiss();
mEditText.setText(selectedValue);
}
return solution;
}
});
return view;
}
}
I'm trying to create a numberpicker in Android but the wheel only increase by 1. I want to increase by 0.1. I've looked up on the net but I've found a formated array of floats disabling the wheel. Please help and sorry for the grammar, I'm learning.
You can do it with custom strings:
NumberPicker picker = new NumberPicker(this);
picker.setMinValue(0);
picker.setMaxValue(100);
picker.setDisplayedValues( new String[] { "0.0", "0.1", ..., "10.0" } );
double = picker.getValue() / 10.0;
You can create your own DecimalPicker view based on ElegantNumberButton.
Add following classes to your project:
/path/to/your/DecimalPicker.java
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import ru.alanov.cashbox.R;
import ru.alanov.cashbox.Utils;
public class DecimalPicker extends RelativeLayout {
private Context context;
private AttributeSet attrs;
private int styleAttr;
private OnClickListener mListener;
private double initialNumber, finalNumber, lastNumber, currentNumber;
private EditText editText;
private String format;
private OnValueChangeListener onValueChangeListener;
public DecimalPicker(Context context) {
super(context);
this.context = context;
initView();
}
public DecimalPicker(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.attrs = attrs;
initView();
}
public DecimalPicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
this.attrs = attrs;
this.styleAttr = defStyleAttr;
initView();
}
private void initView(){
inflate(context, R.layout.decimal_picker, this);
final Resources res = getResources();
final int defaultColor = res.getColor(R.color.colorPrimary);
final int defaultTextColor = res.getColor(R.color.colorText);
final Drawable defaultDrawable = res.getDrawable(R.drawable.decimal_picker_shape);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DecimalPicker, styleAttr, 0);
initialNumber = a.getInt(R.styleable.DecimalPicker_initialNumber, 0);
finalNumber = a.getInt(R.styleable.DecimalPicker_finalNumber, Integer.MAX_VALUE);
float textSize = a.getDimension(R.styleable.DecimalPicker_textSize, 24);
int color = a.getColor(R.styleable.DecimalPicker_backGroundColor,defaultColor);
int textColor = a.getColor(R.styleable.DecimalPicker_textColor,defaultTextColor);
Drawable drawable = a.getDrawable(R.styleable.DecimalPicker_backgroundDrawable);
Button buttonMinus = (Button) findViewById(R.id.subtract_btn);
Button buttonPlus = (Button) findViewById(R.id.add_btn);
editText = (EditText) findViewById(R.id.number_counter);
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT) {
String num = ((EditText) v).getText().toString();
setNumber(num, true);
}
return false;
}
});
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
String value = s.toString().trim();
double valueDouble = -1;
try {
valueDouble = parseDouble(value.isEmpty() ? "0" : value);
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (valueDouble >= 0){
lastNumber = currentNumber;
currentNumber = valueDouble;
callListener(DecimalPicker.this);
}
}
});
LinearLayout mLayout = (LinearLayout) findViewById(R.id.decimal_picker_layout);
buttonMinus.setTextColor(textColor);
buttonPlus.setTextColor(textColor);
editText.setTextColor(textColor);
buttonMinus.setTextSize(textSize);
buttonPlus.setTextSize(textSize);
editText.setTextSize(textSize);
if (drawable == null){
drawable = defaultDrawable;
}
assert drawable != null;
drawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC));
if (Build.VERSION.SDK_INT > 16)
mLayout.setBackground(drawable);
else
mLayout.setBackgroundDrawable(drawable);
editText.setText(String.valueOf(initialNumber));
currentNumber = initialNumber;
lastNumber = initialNumber;
buttonMinus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View mView) {
double num = parseDouble(editText.getText().toString());
setNumber(String.valueOf(num - 1)/*, true*/);
}
});
buttonPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View mView) {
double num = parseDouble(editText.getText().toString());
setNumber(String.valueOf(num + 1)/*, true*/);
}
});
a.recycle();
}
private void callListener(View view){
if (mListener != null)
mListener.onClick(view);
if (onValueChangeListener != null && lastNumber != currentNumber)
onValueChangeListener.onValueChange(this, lastNumber, currentNumber);
}
public String getNumber(){
return String.valueOf(currentNumber);
}
public void setNumber(String number) {
try {
double n = parseDouble(number);
if (n > finalNumber)
n = finalNumber;
if (n < initialNumber)
n = initialNumber;
if (format != null) {
String num = String.format(Utils.getCurrentLocale(getContext()), format, n);
num = removeTrailingZeroes(num);
editText.setText(num);
} else
editText.setText(String.valueOf(number));
lastNumber = currentNumber;
currentNumber = parseDouble(editText.getText().toString());
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
private double parseDouble(String str) throws NumberFormatException {
return Double.parseDouble(str.replace(",","."));
}
private String removeTrailingZeroes(String num) {
NumberFormat nf = NumberFormat.getInstance();
if (nf instanceof DecimalFormat) {
DecimalFormatSymbols sym = ((DecimalFormat) nf).getDecimalFormatSymbols();
char decSeparator = sym.getDecimalSeparator();
String[] split = num.split((decSeparator == '.' ? "\\" : "") + String.valueOf(decSeparator));
if (split.length == 2 && split[1].replace("0", "").isEmpty())
num = split[0];
}
return num;
}
public void setNumber(String number, boolean notifyListener){
setNumber(number);
if (notifyListener)
callListener(this);
}
public void setOnClickListener(OnClickListener onClickListener) {
mListener = onClickListener;
}
public void setOnValueChangeListener(OnValueChangeListener onValueChangeListener){
this.onValueChangeListener = onValueChangeListener;
}
public interface OnClickListener {
void onClick(View view);
}
public interface OnValueChangeListener {
void onValueChange(DecimalPicker view, double oldValue, double newValue);
}
public void setRange(Double startingNumber, Double endingNumber) {
initialNumber = startingNumber;
finalNumber = endingNumber;
}
public void setFormat(String format){
this.format = format;
}
}
/layout/decimal_picker.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:id="#+id/decimal_picker_layout"
android:layout_height="wrap_content">
<Button
android:id="#+id/subtract_btn"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="-"
android:background="#android:color/transparent" />
<EditText
android:id="#+id/number_counter"
android:gravity="center"
android:imeOptions="flagNoExtractUi"
android:inputType="numberDecimal"
android:text = "1"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#android:color/transparent" />
<Button
android:id="#+id/add_btn"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="+"
android:background="#android:color/transparent" />
</LinearLayout>
/drawable/decimal_picker_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="4dp" />
</shape>
/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DecimalPicker">
<attr name="backGroundColor" format="color"/>
<attr name="initialNumber" format="integer"/>
<attr name="finalNumber" format="integer" />
<attr name="textColor" format="color"/>
<attr name="textSize" format="dimension"/>
<attr name="backgroundDrawable" format="reference"/>
<attr name="decimalFormat" format="reference"/>
</declare-styleable>
</resources>
In /values/colors.xml add <color name="colorText">#FFFFFF</color>
Usage example:
In your activity layout place
<path.to.your.DecimalPicker
android:id="#+id/decimal_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"/>
In your Activity#onCreate() place
DecimalPicker decimalPicker = (DecimalPicker) view.findViewById(R.id.decimal_picker);
decimalPicker.setFormat("%.3f");//Weight format
decimalPicker.setOnValueChangeListener(new DecimalPicker.OnValueChangeListener() {
#Override
public void onValueChange(DecimalPicker picker, double oldValue, double newValue) {
//Do what you want to handle value change.
}
});
The result of efforts:
Click on +/- will change integer part of number. If you want to change fractional part - click on number and edit it by hands. If there is no fractional part you will see a integer part only without zeroes.
Alternatively you can use this handy NumberPicker Kotlin extension dialog which scales your Double values into a fitting Int range and converts the Int values back to Doubles before calling any of the callback. It basicallly hides away the fact that NumberPicker only supports Int and adds support for Double!
Here's the Fragment extension you need to copy & paste:
fun Fragment.showNumberPickerDialog(
title: String,
value: Double,
range: ClosedRange<Double>,
stepSize: Double,
formatToString: (Double) -> String,
valueChooseAction: (Double) -> Unit
) {
val numberPicker = NumberPicker(context).apply {
setFormatter { formatToString(it.toDouble() * stepSize) }
wrapSelectorWheel = false
minValue = (range.start / stepSize).toInt()
maxValue = (range.endInclusive / stepSize).toInt()
this.value = (value.toDouble() / stepSize).toInt()
// NOTE: workaround for a bug that rendered the selected value wrong until user scrolled, see also: https://stackoverflow.com/q/27343772/3451975
(NumberPicker::class.java.getDeclaredField("mInputText").apply { isAccessible = true }.get(this) as EditText).filters = emptyArray()
}
MaterialAlertDialogBuilder(context)
.setTitle(title)
.setView(numberPicker)
.setPositiveButton("OK") { _, _ -> valueChooseAction(numberPicker.value.toDouble() * stepSize) }
.setNeutralButton("Cancel") { _, _ -> /* do nothing, closes dialog automatically */ }
.show()
}
Then use it like this:
showNumberPickerDialog(
title = "Your Weight",
value = 75.0, // in kilograms
range = 10.0 .. 300.0,
formatToString = { "$it kg" },
valueChooseAction = { saveNewWeight(it) }
)
I´ve succesfully implemented the RangeSeekbar from this website ( http://code.google.com/p/range-seek-bar/) into my App.
The Problem alot of people now have tho, is that we can´t find an onProgressChanged Method for the two thumbs in the code for the RangeSeekbar.
Do i have to write my own onProgressChanged?
I implemented the RangeSeekbar into a DialogFragment. For the normal Seekbar everything worked fine.
http://www.directupload.net/file/d/3582/mokh6mkb_jpg.htm <-- How can I get the two TextViews to the left and right of "to" to show the selected Value of the RangeSeekbar?
My Code so far:
package com.example.test2;
import com.example.test2.RangeSeekBar.OnRangeSeekBarChangeListener;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
public class LookingAgeFragment extends DialogFragment implements View.OnClickListener, OnRangeSeekBarChangeListener {
protected static final String TAG = null;
public static String username;
static int lowestAge;
static int highestAge;
static TextView viewTo, viewMaxAge, viewMinAge;
RangeSeekBar<Integer> seekBar;
public void onAttach(Activity activity){
super.onAttach(activity);
}
public void onCeate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view= inflater.inflate(R.layout.fragment_age_looking,null);
getDialog().setTitle(getString(R.string.lookingage_title));
Button button = (Button)view.findViewById(R.id.buttonLeaveFragmentLookingAge);
viewTo = (TextView)view.findViewById(R.id.textView_to);
viewMaxAge = (TextView)view.findViewById(R.id.textView_maxAge);
viewMinAge = (TextView)view.findViewById(R.id.textView_minAge);
button.setOnClickListener(this);
// create RangeSeekBar as Integer range between 20 and 75
seekBar = new RangeSeekBar<Integer>(20, 75, getActivity());
seekBar.setOnRangeSeekBarChangeListener(new OnRangeSeekBarChangeListener<Integer>() {
#Override
public void onRangeSeekBarValuesChanged(RangeSeekBar<?> bar, Integer minValue, Integer maxValue) {
// handle changed range values
Log.i(TAG, "User selected new range values: MIN=" + minValue + ", MAX=" + maxValue);
}
});
ViewGroup layout = (ViewGroup) view.findViewById(R.id.rangeSeekbarContainer);
layout.addView(seekBar);
setUpLayout();
return view;
}
#SuppressLint("NewApi")
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
Bundle bundle = this.getArguments();
if(bundle != null){
username = bundle.getString("username", null);
}
}
private void setUpLayout() {
// TODO Auto-generated method stub
setCancelable(false);
//bar.setOnSeekBarChangeListener(yourSeekBarListener);
}
public void saveDataChange(String s, String data){
String help = "com.example.test2.PREFERENCE_FILE_KEY_"+username;
Context context = getActivity();
SharedPreferences sharedPref = context.getSharedPreferences(help, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(s, data);
editor.commit();
}
public String getData(String s){
String data;
String help = "com.example.test2.PREFERENCE_FILE_KEY_"+username;
Context context = getActivity();
SharedPreferences sharedPref = context.getSharedPreferences(help, Context.MODE_PRIVATE);
data = sharedPref.getString(s, null);
return data;
}
#Override
public void onClick(View view) {
// TODO Auto-generated method stub
switch(view.getId()){
case R.id.buttonLeaveFragmentLookingAge:
dismiss();
break;
}
}
public void onProgressChanged() {
// TODO Auto-generated method stub
int maxvalue = (Integer) seekBar.getSelectedMaxValue();
viewMaxAge.setText(maxvalue);
int minvalue = (Integer) seekBar.getSelectedMinValue();
viewMinAge.setText(minvalue);
}
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
public void onStopTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
int maxvalue = (Integer) seekBar.getSelectedMaxValue();
viewMaxAge.setText(maxvalue);
int minvalue = (Integer) seekBar.getSelectedMinValue();
viewMinAge.setText(minvalue);
}
public void onRangeSeekBarValuesChanged(RangeSeekBar bar, Object minValue,
Object maxValue) {
// TODO Auto-generated method stub
viewMaxAge.setText((String)maxValue);
viewMinAge.setText((String)minValue);
}
}
Thank you for your help.
RangeSeekbar is a generic class. if your pass T parameter to it as type of range values, then RangSeekBar pass left thumb Value as minValue and right thumb Value as maxValue in
RangeSeekBar.OnRangeSeekBarChangeListener.(RangeSeekBar bar, T minValue, T maxValue).
change line of your class extends to:
public class LookingAgeFragment extends DialogFragment implements OnRangeSeekBarChangeListener<Integer>
after that you should change Object to Integer in your code at this line
seekBar.setOnRangeSeekBarChangeListener(new RangeSeekBar.OnRangeSeekBarChangeListener<Integer>() {
#Override
public void onRangeSeekBarValuesChanged(RangeSeekBar<?> bar, Integer minValue, Integer maxValue) {
viewMinAge.setText(String.valueOf(minValue));
viewMaxAge.setText(String.valueOf(minValue));
}
});
I think by this changes your problem will be solved.
for more generic solution when your ages range is not continuous and maybe discrete, I suggest this solution
public class LookingAgeFragment extends DialogFragment implements RangeSeekBar.OnRangeSeekBarChangeListener<Integer> {
RangeSeekBar<Integer> seekBar;
int[] ageValues={10, 20, 30, 50, 100};
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
// create RangeSeekBar as Integer range between 20 and 75
seekBar = new RangeSeekBar<Integer>(0, ageValues.length - 1, getActivity());
seekBar.setOnRangeSeekBarChangeListener(new RangeSeekBar.OnRangeSeekBarChangeListener<Integer>() {
#Override
public void onRangeSeekBarValuesChanged(RangeSeekBar<?> bar, Integer minValue, Integer maxValue) {
viewMinAge.setText(String.valueOf(ageValues[minValue]));
viewMaxAge.setText(String.valueOf(ageValues[minValue]));
}
});
}
}
I use next code for getting the values on changing event:
rangeSeekBar.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("MinValue", rangeSeekBar.getSelectedMinValue().toString());
Log.d("MaxValue", rangeSeekBar.getSelectedMaxValue().toString());
return false;
}
});
In class ReangeSekkBar you have this if in ACTION_MOVE
if (notifyWhileDragging && listener != null) {
listener.onRangeSeekBarValuesChanged(this, getSelectedMinValue(), getSelectedMaxValue());
}
delete this if
//if (notifyWhileDragging && listener != null) {
listener.onRangeSeekBarValuesChanged(this, getSelectedMinValue(), getSelectedMaxValue());
//}
I am creating a live wallpaper settings activity. It has a few seek bars and an Ad Mob ad view. Every time I touch one of the seek bars the ad temporarily disappears and then reloads a new add. However, the ad does not change when any of the other preferences are touched. How do I stop the ad from reloading when a seek bar preference is touched? I am pretty stumped on this one :-). Code follows:
The ad preference class:
import android.app.Activity;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;
public class AdPreference extends Preference {
public AdPreference(Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle);}
public AdPreference(Context context, AttributeSet attrs) {super(context, attrs);}
public AdPreference(Context context) {super(context);}
#Override
protected View onCreateView(ViewGroup parent) {
// this will create the linear layout defined in ads_layout.xml
View view = super.onCreateView(parent);
// the context is a PreferenceActivity
Activity activity = (Activity)getContext();
// Create the adView
AdView adView = new AdView(activity, AdSize.BANNER, "a151390e12917b5");
((LinearLayout)view).addView(adView);
// Initiate a generic request to load it with an ad
AdRequest request = new AdRequest();
request.addTestDevice("23392C83B8B55DE893A18286CB92DDA2");
request.addTestDevice("E1BAA0317138AEE05268B2E4F76B2D3F");
adView.loadAd(request);
return view;
}
}
The seek bar class:
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class SeekBarPreference extends Preference implements OnSeekBarChangeListener {
private final String TAG = getClass().getName();
private static final String ANDROIDNS="http://schemas.android.com/apk/res/android";
private static final String ROBOBUNNYNS="http://robobunny.com";
private static final int DEFAULT_VALUE = 50;
private int mMaxValue = 100;
private int mMinValue = 0;
private int mInterval = 1;
private int mCurrentValue;
private String mUnitsLeft = "";
private String mUnitsRight = "";
private SeekBar mSeekBar;
private TextView mStatusText;
public SeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initPreference(context, attrs);
}
public SeekBarPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initPreference(context, attrs);
}
private void initPreference(Context context, AttributeSet attrs) {
setValuesFromXml(attrs);
mSeekBar = new SeekBar(context, attrs);
mSeekBar.setMax(mMaxValue - mMinValue);
mSeekBar.setOnSeekBarChangeListener(this);
}
private void setValuesFromXml(AttributeSet attrs) {
mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", 100);
mMinValue = attrs.getAttributeIntValue(ROBOBUNNYNS, "min", 0);
mUnitsLeft = getAttributeStringValue(attrs, ROBOBUNNYNS, "unitsLeft", "");
String units = getAttributeStringValue(attrs, ROBOBUNNYNS, "units", "");
mUnitsRight = getAttributeStringValue(attrs, ROBOBUNNYNS, "unitsRight", units);
try {
String newInterval = attrs.getAttributeValue(ROBOBUNNYNS, "interval");
if(newInterval != null)
mInterval = Integer.parseInt(newInterval);
}
catch(Exception e) {
Log.e(TAG, "Invalid interval value", e);
}
}
private String getAttributeStringValue(AttributeSet attrs, String namespace, String name, String defaultValue) {
String value = attrs.getAttributeValue(namespace, name);
if(value == null)
value = defaultValue;
return value;
}
#Override
protected View onCreateView(ViewGroup parent){
RelativeLayout layout = null;
try {
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (RelativeLayout)mInflater.inflate(R.layout.seek_bar_preference, parent, false);
}
catch(Exception e)
{
Log.e(TAG, "Error creating seek bar preference", e);
}
return layout;
}
#Override
public void onBindView(View view) {
super.onBindView(view);
try
{
// move our seekbar to the new view we've been given
ViewParent oldContainer = mSeekBar.getParent();
ViewGroup newContainer = (ViewGroup) view.findViewById(R.id.seekBarPrefBarContainer);
if (oldContainer != newContainer) {
// remove the seekbar from the old view
if (oldContainer != null) {
((ViewGroup) oldContainer).removeView(mSeekBar);
}
// remove the existing seekbar (there may not be one) and add ours
newContainer.removeAllViews();
newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
catch(Exception ex) {
Log.e(TAG, "Error binding view: " + ex.toString());
}
updateView(view);
}
/**
* Update a SeekBarPreference view with our current state
* #param view
*/
protected void updateView(View view) {
try {
RelativeLayout layout = (RelativeLayout)view;
mStatusText = (TextView)layout.findViewById(R.id.seekBarPrefValue);
mStatusText.setText(String.valueOf(mCurrentValue));
mStatusText.setMinimumWidth(30);
mSeekBar.setProgress(mCurrentValue - mMinValue);
TextView unitsRight = (TextView)layout.findViewById(R.id.seekBarPrefUnitsRight);
unitsRight.setText(mUnitsRight);
TextView unitsLeft = (TextView)layout.findViewById(R.id.seekBarPrefUnitsLeft);
unitsLeft.setText(mUnitsLeft);
}
catch(Exception e) {
Log.e(TAG, "Error updating seek bar preference", e);
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newValue = progress + mMinValue;
if(newValue > mMaxValue)
newValue = mMaxValue;
else if(newValue < mMinValue)
newValue = mMinValue;
else if(mInterval != 1 && newValue % mInterval != 0)
newValue = Math.round(((float)newValue)/mInterval)*mInterval;
// change rejected, revert to the previous value
if(!callChangeListener(newValue)){
seekBar.setProgress(mCurrentValue - mMinValue);
return;
}
// change accepted, store it
mCurrentValue = newValue;
mStatusText.setText(String.valueOf(newValue));
persistInt(newValue);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
notifyChanged();
}
#Override
protected Object onGetDefaultValue(TypedArray ta, int index){
int defaultValue = ta.getInt(index, DEFAULT_VALUE);
return defaultValue;
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if(restoreValue) {
mCurrentValue = getPersistedInt(mCurrentValue);
}
else {
int temp = 0;
try {
temp = (Integer)defaultValue;
}
catch(Exception ex) {
Log.e(TAG, "Invalid default value: " + defaultValue.toString());
}
persistInt(temp);
mCurrentValue = temp;
}
}
}
The xml layout for the settings activity:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:robobunny="http://robobunny.com"
android:key="disco_wormhole_settings" >
<com.package.name.and.AdPreference
android:layout_width="fill_parent"
androidLlayout_height="wrap_content" />
<Preference
android:key="title"
android:summary="#string/settings_summary"
android:title="#string/settings_title" />
<com.package.name.and.SeekBarPreference
android:defaultValue="50"
android:key="flight_speed"
android:max="100"
android:progressDrawable="#drawable/seek_bar_progress"
android:summary="#string/flight_speed_summary"
android:title="#string/flight_speed_title"
robobunny:min="1"
robobunny:unitsLeft=""
robobunny:unitsRight="%" />
<com.package.name.and.SeekBarPreference
android:defaultValue="30"
android:key="num_rings"
android:max="40"
android:progressDrawable="#drawable/seek_bar_progress"
android:summary="#string/num_rings_summary"
android:title="#string/num_rings_title"
robobunny:min="1"
robobunny:unitsLeft=""
robobunny:unitsRight="" />
<com.package.name.and.SeekBarPreference
android:defaultValue="50"
android:key="particle_speed"
android:max="100"
android:progressDrawable="#drawable/seek_bar_progress"
android:summary="#string/particle_speed_summary"
android:title="#string/particle_speed_title"
robobunny:min="1"
robobunny:unitsLeft=""
robobunny:unitsRight="%" />
<Preference
android:summary="#string/colors_summary"
android:title="#string/colors_title" >
</Preference>
<Preference
android:defaultValue="0xff7d9fff"
android:key="color_one"
android:title="#string/color_one" >
</Preference>
<Preference
android:defaultValue="0xffff4b31"
android:key="color_two"
android:title="#string/color_two" >
</Preference>
<Preference
android:defaultValue="0xff64ff46"
android:key="color_three"
android:title="#string/color_three" >
</Preference>
<CheckBoxPreference
android:defaultValue="true"
android:key="use_space_dust"
android:title="#string/use_space_dust_title" />
<Preference
android:key="spacer"
android:title="#string/single_space" />
<Preference>
</Preference>
</PreferenceScreen>
Thanks in advance for your help,
Chris
I think onCreateView will be called multiple times so an ad request will be created every time. Try moving your admob code to something like onBind or onAttached.
I'm using a custom dialog preference to generate a seekbar in my preferences menu.
After researching seekbar implementation, to obtain the float value I need from the seekbar I have written the following code:
public void onProgressChanged(SeekBar seek, int newValue,
boolean fromTouch) {
// Round the value to the closest integer value.
if (stepSize >= 1) {
value = Math.round(newValue/stepSize)*stepSize;
}
else {
value = newValue;
}
// Set the valueText text.
float sValue = newValue*10;
sValue = sValue/100;
valueText.setText(Float.toString(sValue));
Which produces the float that I want. However, I want to be able to use this float in my main activity. I have attempted to store it using SharedPreferences using:
userPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
Editor editor = userPrefs.edit()
editor.putFloat("mpm", sValue);
editor.commit();
Which is how I've learned to use SharedPreferences in a class extending Activity.
However as this seekbar extends Dialogue Preference I cannot use
getBaseContext()
As I get the error that the method getBaseContext is undefined for this type.
I have tried changing getBaseContext() to getContext() but this has been unsuccessful although that may be because I am unfamiliar with this implementation.
How can I save this float from the dialogue preference and use the value in a different class?
The code I am using to retrieve SharedPreferences:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.logbook);
initialise();
userPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
list = userPrefs.getString("list", "10");
userswallstring = userPrefs.getString("height", "10.0");
try {
usersWall = Float.valueOf(userswallstring.trim());
} catch (Exception e) {
// TODO: handle exception
}
mpm = userPrefs.getFloat("mpm", 2);
Mpm.class:
package com.gbclimber.ep;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
public class Mpm extends
DialogPreference implements SeekBar.OnSeekBarChangeListener {
// Layout widgets.
private SeekBar seekBar = null;
private TextView valueText = null;
// Custom xml attributes.
private int maximumValue = 0;
private int minimumValue = 0;
private int stepSize = 0;
private String units = null;
private int value = 0;
SharedPreferences userPrefs;
/**
* The SeekBarDialogPreference constructor.
* #param context of this preference.
* #param attrs custom xml attributes.
*/
public Mpm(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.Mpm);
maximumValue = typedArray.getInteger(
R.styleable.Mpm_maximumValue, 0);
minimumValue = typedArray.getInteger(
R.styleable.Mpm_minimumValue, 0);
stepSize = typedArray.getInteger(
R.styleable.Mpm_stepSize, 1);
units = typedArray.getString(
R.styleable.Mpm_units);
typedArray.recycle();
}
/**
* {#inheritDoc}
*/
protected View onCreateDialogView() {
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
View view = layoutInflater.inflate(
R.layout.mpmdp, null);
seekBar = (SeekBar)view.findViewById(R.id.seekbar);
valueText = (TextView)view.findViewById(R.id.valueText);
// Get the persistent value and correct it for the minimum value.
value = getPersistedInt(minimumValue) - minimumValue;
// You're never know...
if (value < 0) {
value = 0;
}
seekBar.setOnSeekBarChangeListener(this);
seekBar.setKeyProgressIncrement(stepSize);
seekBar.setMax(maximumValue - minimumValue);
seekBar.setProgress(value);
return view;
}
/**
* {#inheritDoc}
*/
public void onProgressChanged(SeekBar seek, int newValue,
boolean fromTouch) {
// Round the value to the closest integer value.
if (stepSize >= 1) {
value = Math.round(newValue/stepSize)*stepSize;
}
else {
value = newValue;
}
// Set the valueText text.
float sValue = newValue*10;
sValue = sValue/100;
userPrefs = PreferenceManager
.getDefaultSharedPreferences(getContext());
Editor editor = userPrefs.edit();
editor.putFloat("mpm", sValue);
editor.commit();
valueText.setText(Float.toString(sValue));
callChangeListener(value);
}
/**
* {#inheritDoc}
*/
public void onStartTrackingTouch(SeekBar seek) {
}
/**
* {#inheritDoc}
*/
public void onStopTrackingTouch(SeekBar seek) {
}
/**
* {#inheritDoc}
*/
public void onClick(DialogInterface dialog, int which) {
// if the positive button is clicked, we persist the value.
if (which == DialogInterface.BUTTON_POSITIVE) {
if (shouldPersist()) {
persistInt(value + minimumValue);
}
}
super.onClick(dialog, which);
}
#Override
protected void onDialogClosed(boolean positiveResult) {
// TODO Auto-generated method stub
super.onDialogClosed(positiveResult);
persistInt(value + minimumValue);
}
}
Just did a quick search but for your context try
this.getDialog().getContext()