Is it possible to combine an EditTextPreference with a CheckBoxPreference? - android

I have a PreferenceActivity with, among other things, a category including call forward options. What I want is a preference that:
Enables/Disables if the user presses a checkbox on the right.
Opens up the EditTextPreference dialog if the user presses the text(or anything else in the preference)
It's probably not of any use but here is a snippet of this particular preferencecategory :
<PreferenceCategory
android:title="#string/category_callforward">
<EditTextPreference
android:key="call_forward_always"
android:title="#string/call_forward_always"
android:summary="#string/call_forward_forwardto" />
</PreferenceCategory>
EDIT
I'd like to implement it in this method if possible:
// Locates the correct data from saved preferences and sets input type to numerics only
private void setCallForwardType()
{
ep1 = (EditTextPreference) findPreference("call_forward_always");
EditText et = (EditText) ep1.getEditText();
et.setKeyListener(DigitsKeyListener.getInstance());
}
EDIT2
If anyone is still wondering - this is what I want as a Preference:
EDIT3
I've searched around for a couple hours now and have come up with a single word: 'PreferenceGroupAdapter'. I have not, however, been able to find examples or tutorials showing me how to use it. Suggestions ? Is this even the correct path to go?
EDIT4
If this really isn't possibly I would very much like a suggestion to an alternative(user-friendly) solution that I can implement instead of the combined Edit- and Checkbox preference.

You can do this. First, create a class for preferences which should be extended from PreferenceActivity. Use like this:
// editbox ise your EditTextPreference, so set it.
checkbox = (CheckBoxPreference) findPreference("checkbox_preference");
checkbox.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
if(newValue.toString().equals("false")) {
PrefActivity.this.editbox.setEnabled(false);
} else if(newValue.toString().equals("true")) {
PrefActivity.this.editbox.setEnabled(true);
}
return true;
}
});
I hope it helps.

A bit late but I think I've managed to create something similar with a dialog that creates a layout with an edit text and a checkbox, it should be possible to do the same in a normal layout:
public class CheckEditTextPreference extends DialogPreference {
private static final String KEY_PROPERTY_DISABLED = "key_property_disabled";
private EditText editText;
private CheckBox checkBox;
private String text;
private boolean isDisabled;
private SharedPreferences mySharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
public CheckEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected View onCreateDialogView() {
return buildUi();
}
/**
* Build a dialog using an EditText and a CheckBox
*/
private View buildUi() {
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(25, 0, 0, 0);
LinearLayout linearLayout = new LinearLayout(getContext());
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setLayoutParams(layoutParams);
checkBox = new CheckBox(getContext());
editText = new EditText(getContext());
editText.setLayoutParams(layoutParams);
checkBox.setLayoutParams(layoutParams);
checkBox.setText("Disabled");
FrameLayout dialogView = new FrameLayout(getContext());
linearLayout.addView(editText);
linearLayout.addView(checkBox);
dialogView.addView(linearLayout);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
editText.setEnabled(!isChecked);
}
});
return dialogView;
}
#Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
checkBox.setChecked(isDisabled());
editText.setText(getText());
}
#Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
String text = editText.getText().toString();
boolean isChecked = checkBox.isChecked();
if (callChangeListener(text)) {
setText(text);
}
if (callChangeListener(isChecked)) {
isDisabled(isChecked);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
#Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
setText(restorePersistedValue ? getPersistedString("") : defaultValue.toString());
isDisabled(mySharedPreferences.getBoolean(KEY_PROPERTY_DISABLED, true));
}
public void setText(String value) {
this.text = value;
persistString(this.text);
}
public String getText() {
return this.text;
}
private void isDisabled(boolean value) {
this.isDisabled = value;
mySharedPreferences.edit().putBoolean(KEY_PROPERTY_DISABLED, this.isDisabled).apply();
}
public boolean isDisabled() {
return this.isDisabled;
}
}
And put this into your preferences screen:
<your.package.name.CheckEditTextPreference
android:key="chkEtPref"
android:title="Title"/>

Define a key in res/values/strings.xml for your CheckBoxPreference.
Give your CheckBoxPreference the XML attribute android:key="#string/THE_KEY_YOU_DEFINED" so that it will automatically save state in SharedPreferences.
Give your EditTextPreference the XML attribute android:dependency="#string/THE_KEY_YOU_DEFINED.
The EditTextPreference should then enable / disable depending on the state of the CheckBoxPreference.

Related

Android adding event to a CustomPreference element (TextView)

I'm doing an with a PreferenceActivity with two Fragments, each one containing a PreferenceScreen.
The thing I want to do is to create an event listener on a Custom preference that I have (a row of this custom Preference is a TextView with a SwitchView). I handle well the Switch preference, it keeps it saved as I want, but now what I want to do is add an event on the TextView between the SwitchView to show what I want on the other part of the screen (the second Fragment).
Let me show you my current code.
This is my CustomPreference (it's just a TextView and a Switch)
public class ItemPreference extends Preference{
private static TextView text; // this is the text at the left of the switch, it's where i want to handle the event
// to show an other preferencescreen in the fragment between
private Switch switcher; // the key of the preference is for the SWITCH !!
private boolean checked;
private Context context;
public TextView getCustomText(){
return text;
}
public ItemPreference(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
setLayoutResource(R.layout.row_setting); // the layout resource of my custom preference
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
text = (TextView)view.findViewById(R.id.buttonRowSetting);
// to display the text in the TextView between the Switch, I use the key of the Switch
if (this.getKey().equals("pref_key_classification"))
text.setText(R.string.title_activity_classification);
// the switchview and it's preference saving
switcher = (Switch)view.findViewById(R.id.switchRowSetting);
Boolean value = this.getPersistedBoolean(false);
if (value){
switcher.setChecked(true);
} else {
switcher.setChecked(false);
}
switcher.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setSwitchChecked(isChecked);
}
});
}
public void setSwitchChecked(boolean value) {
if (checked != value) {
checked = value;
persistBoolean(value);
notifyDependencyChange(shouldDisableDependents());
notifyChanged();
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getBoolean(index, false);
}
#Override
protected void onClick() {
super.onClick();
}
#Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
setSwitchChecked(restorePersistedValue ? getPersistedBoolean(checked) : (Boolean) defaultValue);
}
#Override
protected Parcelable onSaveInstanceState() {
return super.onSaveInstanceState();
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
}
}
This is the SettingsFragment, on the left part of the screen, where I want to handle the event to show what I want on the other part of the screen.
public class SettingsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings); // the left preferencefragment
Preference stat = (Preference) findPreference(getString(R.string.pref_key_statistic));
stat.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
if(getActivity() instanceof OnSettingPageListener){
// if i click on this preference, this loads this preferencescreen on the other fragment, works well.
((OnSettingPageListener)getActivity()).onSettingPageChange(R.xml.settings_stat);
}
return true;
}
});
// this is the custompreference, i would like to handle here a listener on the TextView to display a specific preferencescreen on the other fragment
ItemPreference classif = (ItemPreference) findPreference(getString(R.string.pref_key_classification));
// i tried this, and i also tried to make my own Listener also, but doesn't works
classif.getCustomText().setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (getActivity() instanceof OnSettingPageListener){
// the content i want to load on the other fragment
((OnSettingPageListener)getActivity()).onSettingPageChange(R.xml.settings_classification);
}
}
});
}
// [...]
}
So I hope you understand what's my problem, it's just a matter of listener. Does someone has a solution?
I'm not sure if you want the event on your first fragment to show the second fragment (for further editing) or if you want the event to make a change visible to the second fragment.
Let's say you want the change to be visible to the second fragment:
Have your second fragment implement SharedPreference.OnSharedPreferenceChangeListener with method onSharedPreferenceChanged, implemented to do what you want to have happen when the preference in the first fragment changes.
In the second fragment's onResume method, call registerOnSharedPreferenceChangeListener on your SharedPreferences object.
In the second fragment's onPause method, call unregisterOnSharedPreferenceChangeListener on your SharedPreferences object.
Now, if you want to show the second fragment for editing the preference in the first fragment:
Give your preference a fragment attribute that declares the fragment class that edits your preference
Have your first fragment implement PreferenceFragment.OnPreferenceStartFragmentCallback with method onPreferenceStartFragment implemented to instantiate your second fragment and display it. Your PreferenceActivity subclass will invoke this callback when the preference is clicked.
I finally found a solution, my problem was the way the handle a listener on the textview of my custom preference. I followed the observer pattern and made it work on my own listener.
On my fragment I instantiated my CustomSwitchPreference (I just renamed the ItemPreference class you can see upstairs ^^). I called my own listener, you will see the code after.
CustomSwitchPreference classif = (CustomSwitchPreference)
findPreference(getString(R.string.pref_key_classification));
classif.setHandlerListener(new ItemPreferenceTextViewListener() {
#Override
public void onHandle(TextView textView) {
if (getActivity() instanceof OnSettingPageListener){
((OnSettingPageListener)getActivity())
.onSettingPageChange(R.xml.settings_classification);
}
}
});
And there we go for the listener in the CustomPreference class, first create an interface to made your own listener (you can write it in the same file as the CustomPreference class you are doing) :
interface ItemPreferenceTextViewListener {
// the function which is going to be called when we will use our listener
void onHandle(TextView textView);
}
And then in the CustomPreference class you do this :
// you can put the interface here if you want to make it visible
public class CustomSwitchPreference extends Preference {
private static TextView text;
// the key of the preference is for the SWITCH !! this activates or
// not the "game" on the mainscreen
private Switch switcher;
private boolean checked;
// ---------------------------------------------------------------------- \\
// create a listener in your own custom preference
ItemPreferenceTextViewListener itemPreferenceTextViewListener ;
// this is the function to handle the event on the textview of the
// custom preference item, creates the listener
public void setHandlerListener(ItemPreferenceTextViewListener listener) {
itemPreferenceTextViewListener = listener;
}
// to make the event happen on a textview
// (we will pass the right textview in the onBindView(....) )
protected void myEventListener(TextView textView) {
if(itemPreferenceTextViewListener!=null)
itemPreferenceTextViewListener.onHandle(textView);
}
// ---------------------------------------------------------------------- \\
/**
* #param context
* #param attrs
*/
public CustomSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.row_setting);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
// the TextView at the right of the switch, this one
// handles a listener to show the other page preference
text = (TextView)view.findViewById(R.id.buttonRowSetting);
// I called it buttonRowSetting because it will handle an event like a button
// I set the text of this TextView with the
// key preference of the related switch
if (this.getKey().equals("pref_key_classification"))
text.setText(R.string.title_activity_classification);
else if (this.getKey().equals("pref_key_matching"))
text.setText(R.string.title_activity_matching);
else if (this.getKey().equals("pref_key_intruder"))
text.setText(R.string.title_activity_intruder);
else if (this.getKey().equals("pref_key_semantic"))
text.setText(R.string.title_activity_semantic);
// AND HERE it's where it happens, simply make a basic listener
// on the textview, and inside the onClick method, handle your own
// listener, on the TextView you initialized just before)
text.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// just call
itemPreferenceTextViewListener.onHandle(text);
}
});
// ---------------------------------------------------------------------- \\
// to keep the Switch saved in the preferences
switcher = (Switch)view.findViewById(R.id.switchRowSetting);
Boolean value = this.getPersistedBoolean(false);
if (value){
switcher.setChecked(true);
} else {
switcher.setChecked(false);
}
switcher.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
setSwitchChecked(isChecked);
}
});
// ---------------------------------------------------------------------- \\
}
public void setSwitchChecked(boolean value) {
if (checked != value) {
checked = value;
persistBoolean(value);
notifyDependencyChange(shouldDisableDependents());
notifyChanged();
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getBoolean(index, false);
}
#Override
protected void onClick() {
super.onClick();
}
#Override
protected void onSetInitialValue(boolean restorePersistedValue,
Object defaultValue) {
setSwitchChecked(restorePersistedValue
? getPersistedBoolean(checked) : (Boolean) defaultValue);
}
#Override
protected Parcelable onSaveInstanceState() {
return super.onSaveInstanceState();
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
}
}
Hope this helps, it was my mistake I did not called the onHandle method inside the myTextView.onClickListener. Hope this will help one to understand well how the observer pattern works.

EditTextPreference value only refreshed after clicking ListPreference second time

I've been struggling with this issue for a while now so I decided to ask here what I' m doing wrong.
First of all:
- I have a PreferenceFragment with a ListPreference on top and an EditTextPreference below
- The ListPreference is filled with Objects, the values are stored in a file and read from there (this works flawlessly)
- The EditTextPreference should display the value of the in the ListPreference chosen object. And that's the problem: after choosing the value nothing changes so I have to click the ListPreference once more and the value is set correctly. Is this a problem with my Listener?
Here's the code:
public class SettingsTestFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private final String[] pref_key_array = {"pref_key_lp", "pref_key_et""}; // array that contains all the preference keys of changeable values
private final int numberOfEntries = pref_key_array.length;
private Preference[] pref_entries;
String[] entries = {"Value 1", "Value 2", "Value 3"};
String[] entryValues = {"0", "1", "2"};
private int position;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
final SharedPreferences myPreference = PreferenceManager.getDefaultSharedPreferences(getActivity());
final EditTextPreference et = (EditTextPreference) findPreference("pref_key_et");
final ListPreference lp = (ListPreference) findPreference("pref_key_lp");
prepareListPref(lp);
pref_entries = new Preference[numberOfEntries];
for(int i = 0; i < numberOfEntries; i++) {
pref_entries[i] = getPreferenceScreen().findPreference(pref_key_array[i]);
}
lp.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
position = Integer.valueOf(myPreference.getString("pref_key_lp", "0"));
et.setText(entries[position]);
return true;
}
});
Preference.OnPreferenceChangeListener changeListener = new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
position = Integer.valueOf(myPreference.getString("pref_key_lp", "0"));
preference.setSummary(entries[position]);
return true;
}
};
lp.setOnPreferenceChangeListener(changeListener);
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updateSummary(key, pref_key_array, numberOfEntries, pref_entries);
}
#Override
public void onResume() {
super.onResume();
// Set up listener when a key changes
for(int i = 0; i < numberOfEntries; i++) {
updateSummary(pref_key_array[i], pref_key_array, numberOfEntries, pref_entries);
}
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onPause() {
super.onPause();
// Unregister listener every time a key changes
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
public void prepareListPref(ListPreference lp) {
lp.setEntries(entries);
lp.setEntryValues(entryValues);
lp.setDefaultValue("0");
}
public void updateSummary(String key, String[] pref_key_array, int numberOfEntries, Preference[] pref_entries) {
for(int i = 0; i < numberOfEntries; i++) {
if(key.equals(pref_key_array[i])) {
if(pref_entries[i] instanceof EditTextPreference) {
final EditTextPreference currentPreference = (EditTextPreference) pref_entries[i];
pref_entries[i].setSummary(currentPreference.getText());
} else if(pref_entries[i] instanceof ListPreference) {
final ListPreference currentPreference = (ListPreference) pref_entries[i];
pref_entries[i].setSummary(currentPreference.getEntry());
}
break;
}
}
}
}
Summarizing the code for reading from the file and writing the value to the Settings works but only after clicking the ListPreference a second time. Do you have any ideas why?
Thanks
ok, I'm not sure what you are trying to do and what is the problem, so I've made a sample, showing the next thing:
a listPreference that its default value&entry will set the title&summary of an EditTextPreference .
when choosing an item on the ListPreference, it will also update tge title&summary of the EditTextPreference according to the value&entry of the item being selected.
Not sure what to do with the EditTextPreference. This is your choice.
I still think you should consider making a custom Preference class, as you wrote that you intend to use a lot of couples of ListPreference&EditTextPreference.
BTW, code is based on an app that I've made (link here). I've made it so that it will be easy to handle multiple listPreferences easier.
Here's the code:
res/values/strings_activity_settings.xml
<resources>
<string name="pref__custom_app_theme" translatable="false">pref__custom_app_theme</string>
<string name="pref__app_theme" translatable="false">pref__app_theme</string>
<string-array name="pref__app_theme_entries">
<item>#string/cards_light</item>
<item>#string/cards_dark</item>
</string-array>
<string name="pref__app_theme__cards_ui" translatable="false">CARDS_UI</string>
<string name="pref__app_theme__cards_ui_dark" translatable="false">CARDS_UI_DARK</string>
<string name="pref__app_theme_default" translatable="false">#string/pref__app_theme__cards_ui</string>
<string-array name="pref__app_theme_values">
<item>#string/pref__app_theme__cards_ui</item>
<item>#string/pref__app_theme__cards_ui_dark</item>
</string-array>
</resources>
res/values/strings.xml
<resources>
<string name="app_name">My Application</string>
<string name="app_theme">App Theme</string>
<string name="cards_light">cards light</string>
<string name="cards_dark">cards dark</string>
</resources>
res/xml/pref_general.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- theme -->
<ListPreference
android:defaultValue="#string/pref__app_theme_default"
android:entries="#array/pref__app_theme_entries"
android:entryValues="#array/pref__app_theme_values"
android:key="#string/pref__app_theme"
android:title="#string/app_theme"/>
<EditTextPreference android:key="#string/pref__custom_app_theme"/>
</PreferenceScreen>
SettingsActivity.java
public class SettingsActivity extends PreferenceActivity
{
public interface IOnListPreferenceChosenListener
{
public void onChosenPreference(String key,String entry,String value);
}
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
final EditTextPreference editTextPreference=(EditTextPreference)findPreference(getString(R.string.pref__custom_app_theme));
final ListPreference listPreference=prepareListPreference(this,R.string.pref__app_theme,R.array.pref__app_theme_entries,R.array.pref__app_theme_values,R.string.pref__app_theme_default,new IOnListPreferenceChosenListener()
{
#Override
public void onChosenPreference(final String key,final String entry,final String value)
{
editTextPreference.setTitle(value);
editTextPreference.setSummary(entry);
}
});
editTextPreference.setTitle(listPreference.getValue());
editTextPreference.setSummary(listPreference.getEntry());
}
public static ListPreference prepareListPreference(final PreferenceActivity activity,final int prefKeyId,//
final int entriesId,final int valuesId,final int defaultValueId,final IOnListPreferenceChosenListener listener)
{
final String prefKey=activity.getString(prefKeyId);
#SuppressWarnings("deprecation")
final ListPreference pref=(ListPreference)activity.findPreference(prefKey);
final String[] entries=activity.getResources().getStringArray(entriesId);
final String[] values=activity.getResources().getStringArray(valuesId);
final String defaultValue=activity.getResources().getString(defaultValueId);
final String currentValue=PreferenceManager.getDefaultSharedPreferences(activity).getString(prefKey,defaultValue);
for(int i=0;i<values.length;++i)
{
final String value=values[i];
if(TextUtils.equals(currentValue,value))
{
pref.setSummary(entries[i]);
pref.setValueIndex(i);
break;
}
}
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
#Override
public boolean onPreferenceChange(final Preference preference,final Object newValue)
{
final String newValueStr=newValue.toString();
String entryChosen=null;
for(int i=0;i<values.length;++i)
{
final String value=values[i];
if(TextUtils.equals(newValueStr,value))
{
entryChosen=entries[i];
break;
}
}
pref.setSummary(entryChosen);
if(listener!=null)
listener.onChosenPreference(prefKey,entryChosen,newValueStr);
return true;
}
});
return pref;
}
}

NumberPickerPreference - Default value is not loaded

I would like to use a NumberPicker preference.
Basically the code is working as expected. A dialog opens with a NumberPicker. The value can be selected and is saved to the defaulSharedPreferences.
But on the first time the PreferenceActivity is started the default Value is not loaded and I cant figure out why.
Behavior is like this: When I open the PreferenceActivity the summary of the NumberPickerPreference shows -1. When I close the Activity and reopen it again the value stays at -1 (This is as long the defaultSharedPreferences has no Value under the key stored). As soon a Value is selected by the user (or a Value is saved by code under the key into the defaultSharedPreferences) everthing works and the value is loaded when the PreferenceActivity is started.
public class NumberPickerPreference extends DialogPreference implements NumberPicker.OnValueChangeListener
{
private static final String NAMESPACE="http://schemas.android.com/apk/res/android";
private NumberPicker mNumberPicker;
private TextView mTvDialogMessage;
private Context mCtx;
private String mDialogMessage;
private int mDefault;
private int mMax;
private int mValue = 0;
public NumberPickerPreference(Context ctx, AttributeSet attr) {
super(ctx, attr);
mCtx = ctx;
//Get XML attributes
mDialogMessage = attr.getAttributeValue(NAMESPACE,"dialogMessage");
mDefault = attr.getAttributeIntValue(NAMESPACE,"defaultValue", 2);
mMax = attr.getAttributeIntValue(NAMESPACE,"max", 20);
}
#Override
protected View onCreateDialogView() {
//Create Views
LinearLayout dialogLayout = new LinearLayout(mCtx);
mTvDialogMessage = new TextView(mCtx);
mNumberPicker = new NumberPicker(mCtx);
//Set View attributes
dialogLayout.setOrientation(LinearLayout.VERTICAL);
if (mDialogMessage!=null)
mTvDialogMessage.setText(mDialogMessage);
dialogLayout.addView(mTvDialogMessage);
mNumberPicker.setOnValueChangedListener(this);
dialogLayout.addView(mNumberPicker, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
if (shouldPersist())
mValue = getPersistedInt(mDefault);
mNumberPicker.setMaxValue(mMax);
mNumberPicker.setMinValue(1);
mNumberPicker.setValue(mValue);
return dialogLayout;
}
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
mNumberPicker.setMaxValue(mMax);
mNumberPicker.setMinValue(1);
mNumberPicker.setValue(mValue);
setSummary(mValue);
}
#Override
protected void onSetInitialValue(boolean restore, Object defaultValue)
{
super.onSetInitialValue(restore, defaultValue);
if (restore)
mValue = shouldPersist() ? getPersistedInt(mDefault) : 2;
else
mValue = (Integer)defaultValue;
if (mNumberPicker!=null)
mNumberPicker.setValue(mValue);
setSummary(mValue);
}
public void setSummary(int value) {
CharSequence summary = getSummary();
value=getPersistedInt(-1);
if (summary == null) {
setSummary(Integer.toString(value));
} else {
setSummary(String.format(summary.toString(), value));
}
}
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
setSummary(newVal);
if (shouldPersist())
persistInt(newVal);
callChangeListener(new Integer(newVal));
}
}
I was experiencing the same issue. Not sure if it is correct but calling
setDefaultValue(Object);
with my default value in Preference constructor seemed to solve this.
Try adding notifyChanged() after persistInt(newVal)

autosum checkbox

So the thing I am trying to accomplish should be exactly like this : http://www.javascriptbank.com/simple-javascript-auto-sum-with-checkboxes.html/en/
Unfortunately im not shure if thats even possible so I would appreciate any kind of help or idea . Thanks in advance.Some thing that i have so far:
CheckBox chkone;
CheckBox chktwo;
CheckBox chkthree;
TextView tv;
OnClickListener checkBoxListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
chkone = (CheckBox)findViewById(R.id.chk1);
chktwo = (CheckBox)findViewById(R.id.chk2);
thkthree = (CheckBox)findViewById(R.id.chk3);
checkBoxListener = new OnClickListener() {
//#Override
public void onClick(View v) {
tv = (TextView)findViewById(R.id.tv1);
if (chkone.isChecked())
{
// something
}
}
};
chkone.setOnClickListener(checkBoxListener);
chktwo.setOnClickListener(checkBoxListener);
chkthree.setOnClickListener(checkBoxListener);
You should implement the CompoundButton's OnCheckedChangeListener interface instead, to get notifications about the checkbox's state changes.
Assuming that you didn't extend the CheckBox class to ease your work by storing a numeric value somewhere, you need to parse the label (text) of the checkbox in order to access it's value, and based on the checked state increase / decrease the sum:
private TextView sumText;
private float currentSum = 0;
private final OnCheckedChangeListener checkBoxListener =
new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if (isChecked)
currentSum += getNumber(buttonView);
else
currentSum -= getNumber(buttonView);
// TODO: you need to initialize this TextView in your
// onCreate method!
sumText.setText(Float.toString(currentSum));
}
};
private float getNumber(final CompoundButton chk)
{
try
{
return Float.parseFloat(chk.getText().toString());
}
catch (NumberFormatException e)
{
return 0;
}
}
Note, that for this to work as you expect it, you should modify the getNumber method to retrieve the values that is actually under that CheckBox instance!

Disabling rows in ListPreference

I am creating a settings menu for a free version of my app. I have a ListPreference displaying many different options. However, only some of these options are to be made available in the free version (I would like all options to be visible - but disabled, so the user knows what they are missing!).
I'm struggling to disable certain rows of my ListPreference. Does anybody know how this can be achieved?
Solved it.
I made a custom class extending ListPreference. I then used a custom ArrayAdapter and used methods areAllItemsEnabled() and isEnabled(int position).
public class CustomListPreference extends ListPreference {
public CustomListPreference (Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onPrepareDialogBuilder(Builder builder) {
ListAdapter listAdapter = new CustomArrayAdapter(getContext(), R.layout.listitem, getEntries(), resourceIds, index);
builder.setAdapter(listAdapter, this);
super.onPrepareDialogBuilder(builder);
}
}
and
public class CustomArrayAdapter extends ArrayAdapter<CharSequence> {
public CustomArrayAdapter(Context context, int textViewResourceId,
CharSequence[] objects, int[] ids, int i) {
super(context, textViewResourceId, objects);
}
public boolean areAllItemsEnabled() {
return false;
}
public boolean isEnabled(int position) {
if(position >= 2)
return false;
else
return true;
}
public View getView(int position, View convertView, ViewGroup parent) {
...
return row;
}
I searched through and through all over the web, and couldn't find a way to achieve this. The answer above did not help me. I found the entire "ArrayAdapter" method very unintuitive , unhelpful, and hard to implement.
Finally, I actually had to look inside the source code for "ListPreference", to see what they did there, and figure out how to override the default behavior cleanly and efficiently.
I'm sharing my solution below. I made the class "SelectiveListPreference" to inherit the behavior of "ListPreference", but add a positive button, and prevent closing when an option is pressed. There is also a new xml attribute to specify which options are available in the free version.
My trick is not to call ListPreference's version of onPrepareDialogBuilder, but instead implement my own, with a custom click handler. I did not have to write my own code for persisting the selected value, since I used ListPreference's code (that's why I extended "ListPreference" and not "Preference").
The handler looks for the boolean resource "free_version" and if it's true, it only allows the options specified in "entry_values_free" xml attribute. If "free_version" is false, all options are allowed. There's also an empty method for inheritors, if something should happen when an option is chosen.
Enjoy,
Tal
public class SelectiveListPreference extends ListPreference
{
private int mSelectedIndex;
private Collection<CharSequence> mEntryValuesFree;
private Boolean mFreeVersion;
public SelectiveListPreference(Context context)
{
super(context);
}
//CTOR: load members - mEntryValuesFree & mFreeVersion
public SelectiveListPreference(Context context, AttributeSet attrs)
{
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SelectiveListPreference);
try
{
CharSequence[] entryValuesFree = a
.getTextArray(R.styleable.SelectiveListPreference_entryValuesFree);
mEntryValuesFree = new ArrayList<CharSequence>(
Arrays.asList(entryValuesFree));
}
finally
{
a.recycle();
}
Resources resources = context.getResources();
mFreeVersion = resources.getBoolean(R.bool.free_version);
}
//override ListPreference's implementation - make our own dialog with custom click handler, keep the original selected index
#Override
protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder builder)
{
CharSequence[] values = this.getEntries();
mSelectedIndex = this.findIndexOfValue(this.getValue());
builder.setSingleChoiceItems(values, mSelectedIndex, mClickListener)
.setPositiveButton(android.R.string.ok, mClickListener)
.setNegativeButton(android.R.string.cancel, mClickListener);
};
//empty method for inheritors
protected void onChoiceClick(String clickedValue)
{
}
//our click handler
OnClickListener mClickListener = new OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
if (which >= 0)//if which is zero or greater, one of the options was clicked
{
String clickedValue = (String) SelectiveListPreference.this
.getEntryValues()[which]; //get the value
onChoiceClick(clickedValue);
Boolean isEnabled;
if (mFreeVersion) //free version - disable some of the options
{
isEnabled = (mEntryValuesFree != null && mEntryValuesFree
.contains(clickedValue));
}
else //paid version - all options are open
{
isEnabled = true;
}
AlertDialog alertDialog = (AlertDialog) dialog;
Button positiveButton = alertDialog
.getButton(AlertDialog.BUTTON_POSITIVE);
positiveButton.setEnabled(isEnabled);
mSelectedIndex = which;//update current selected index
}
else //if which is a negative number, one of the buttons (positive or negative) was pressed.
{
if (which == DialogInterface.BUTTON_POSITIVE) //if the positive button was pressed, persist the value.
{
SelectiveListPreference.this.setValueIndex(mSelectedIndex);
SelectiveListPreference.this.onClick(dialog,
DialogInterface.BUTTON_POSITIVE);
}
dialog.dismiss(); //close the dialog
}
}
};
}
EDIT: we also need to override the implemented onDialogClosed from ListPreference (and do nothing), otherwise, things valued do not get persisted. Add:
protected void onDialogClosed(boolean positiveResult) {}
Maybe you can do it by overrding default getView:
Steps:
Extend ListPreference
Override onPrepareDialogBuilder and replace mBuilder in DialogPreference with ProxyBuilder
Handle getView in ProxyBuilder->AlertDialog->onShow->getListView->Adapter
Code samples are in custom row in a listPreference?
Having the same problem I found a solution (maybe "hack" is more appropriate). We can register an OnPreferenceClickListener for the ListPreference. Inside this listener we can get the dialog (since the preference was clicked we are pretty safe that it is not null). Having the dialog we can set a OnHierarchyChangeListener on the ListView of the dialog where we are notified when a new child view is added. With the child view at hand we can disable it.
Assuming that the ListView entries are created in the same order as the entry values of the ListPreference we can even get the entry value.
I hope somebody finds this helpful.
public class SettingsFragment extends PreferenceFragment {
private ListPreference devicePreference;
private boolean hasNfc;
#Override
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// load preferences
addPreferencesFromResource(R.xml.preferences);
hasNfc = getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC);
devicePreference = (ListPreference) getPreferenceScreen().findPreference(getString(R.string.pref_device));
// hack to disable selection of internal NFC device when not available
devicePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
final ListPreference listPref = (ListPreference) preference;
ListView listView = ((AlertDialog)listPref.getDialog()).getListView();
listView.setOnHierarchyChangeListener(new OnHierarchyChangeListener() {
// assuming list entries are created in the order of the entry values
int counter = 0;
public void onChildViewRemoved(View parent, View child) {}
public void onChildViewAdded(View parent, View child) {
String key = listPref.getEntryValues()[counter].toString();
if (key.equals("nfc") && !hasNfc) {
child.setEnabled(false);
}
counter++;
}
});
return false;
}
});
}
}

Categories

Resources