How to Fill ListPreference entry and entryvalues From onPreferenceClick event
I Filled From onPreferenceClick event But When First Clicked Getting Empty List
When Second Clicked is Getting All Item.
Why When First Cliked Then Getting Empty List?
thanks.
When setOnPreferenceClickListener is called the dialog seems already created. A possible solution is to extend ListPreference and intercept the click on the view.
package com.example;
import android.preference.ListPreference;
import android.content.Context;
import android.util.AttributeSet;
public class DynamicListPreference extends ListPreference {
public interface DynamicListPreferenceOnClickListener {
public void onClick(DynamicListPreference preference);
}
private DynamicListPreferenceOnClickListener mOnClicListner;
public DynamicListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onClick(){
if (mOnClicListner != null)
mOnClicListner.onClick(this);
super.onClick();
}
public void setOnClickListner(DynamicListPreferenceOnClickListener l) {
mOnClicListner = l;
}
}
The new class have the public method setOnClickListner, you should use it instead of setOnPreferenceClickListener.
Then you can use DynamicListPreference in your xml preference file:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<com.example.DynamicListPreference
android:key="id_list"
android:title="#string/opt_label"
/>
</PreferenceScreen>
In your PreferenceActiviy:
package com.example;
import com.example.DynamicListPreference.DynamicListPreferenceOnClickListener;
import android.preference.ListPreference;
import android.preference.PreferenceActivity;
import android.os.Bundle;
public class MyPreferencesActivity extends PreferenceActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
DynamicListPreference pref = (DynamicListPreference)findPreference("id_list");
pref.setOnClickListner(onClickListener_mylist);
}
private DynamicListPreferenceOnClickListener onClickListener_mylist = new DynamicListPreferenceOnClickListener() {
#Override
public void onClick(DynamicListPreference preference) {
ListPreference pref = (ListPreference) preference;
pref.setEntryValues(new String[] {"1", "2"});
pref.setEntries(new String[] {"first", "second"});
}
};
}
The first idea that popped in my mind. Looks like a very dirty hack to get around, but anyway:
findPreference("yourPreferenceKey").setOnPreferenceClickListener(new OnPreferenceClickListener() {
private final String[] values = {"1","2","3","4"}; // Data set (as an example)
#Override
public boolean onPreferenceClick(final Preference preference) {
((ListPreference)preference).setEntryValues(values); // Set new values
((ListPreference)preference).setEntries(values); // And new keys
final OnPreferenceClickListener prefClickListener = this; // Store the reference to this click listener for a later use
preference.setOnPreferenceClickListener(null); // And remove it from current preference, so it won't cause a recursion when we will emulate user click later
YourPreferenceActivity.this.runOnUiThread(new Runnable(){ // Do some work after current listener finishes it's stuff
#Override
public void run() {
((ListPreference)preference).getDialog().dismiss(); // Dismiss the dialog that popped up because of our first click (with the old data)
YourPreferenceActivity.this.getPreferenceScreen().onItemClick(null, null, preference.getOrder(), 0); // Emulate user click. System will think that user clicked on the same preference again
preference.setOnPreferenceClickListener(prefClickListener); // Let's return our click listener back, so the whole operation will repeat on the next click (delete thi sline if you need preloading only once.
}
});
return false;
}
});
Related
I have a ListPreference in my SettingsFragment and I'd like to display a warning message when the user changes the value with a confirmation button. Only if the user confirms will the ListPreference value actually be changed to the selection. How can I do this?
This is an older question, but here's an answer in case anyone else needs it. First there's an explanation, and at the end there's working code.
If I understand you correctly, you need to add a positive button (e.g. "Ok" or "Yes"), which actually makes the change, instead of making the change immediately when a list item is clicked. Something like this:
Explanation
ListPreference overrides the onClick method of the list items in onPrepareDialogBuilder(Builder builder), so that:
Clicking on an item simulates the positive button click, and dismisses the dialog.
It also overrides the listener of the positive button (i.e. removes it) in the same method, with this explanation:
The typical interaction for list-based dialogs is to have click-on-an-item dismiss the dialog instead of the user having to press 'Ok'.
You need to override it again, but without that functionality. This is the piece of code (inside onPrepareDialogBuilder(Builder builder)) that does that and you want to get rid of:
builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
mClickedDialogEntryIndex = which;
/* Clicking on an item simulates the positive button
* click, and dismisses the dialog. */
ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE); // <--- don't want this
dialog.dismiss(); // <--- don't want this
}
}
);
builder.setPositiveButton(null, null); // <--- don't want this
You also need to apply the change after clicking the positive button, which is done in onDialogClosed(boolean positiveResult).
So you need to create a custom class that extends ListPreference and override onPrepareDialogBuilder(Builder builder) and onDialogClosed(boolean positiveResult).
Code
Here's an example of a ConfirmationListPreference that I use:
package com.your.pckg;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.preference.ListPreference;
import android.util.AttributeSet;
public class ConfirmationListPreference extends ListPreference
{
/** Holds the index of the selected item. */
private int mClickedDialogEntryIndex;
// Constructors; these are standard and required for the subclass
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ConfirmationListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ConfirmationListPreference(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
public ConfirmationListPreference(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ConfirmationListPreference(Context context)
{
super(context);
}
#Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder)
{
// not calling the super method (the one from ListPreference), since
// that's the one that disables the positive button functionality,
// but we'll use most of its code, all except the parts we don't want
if (getEntries() == null || getEntryValues() == null)
{
throw new IllegalStateException("ConfirmationListPreference requires an entries array and an entryValues array.");
}
// get the index of the selected item
mClickedDialogEntryIndex = findIndexOfValue(this.getValue());
builder.setSingleChoiceItems(getEntries(), mClickedDialogEntryIndex,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
// update the index of the selected (clicked) item
mClickedDialogEntryIndex = which;
// the stuff we don't want is removed
// ...
}
}
);
// and don't set the positive button listener to null
// ...
}
#Override
protected void onDialogClosed(boolean positiveResult)
{
// we can't use the super method because mClickedDialogEntryIndex
// is private and there's no setter, so we'll just copy its code
if (positiveResult && mClickedDialogEntryIndex >= 0 && getEntryValues() != null)
{
String value = getEntryValues()[mClickedDialogEntryIndex].toString();
if (callChangeListener(value))
{
setValue(value);
}
}
}
}
And you use it in your preference xml (e.g. pref_general.xml) like this:
<com.your.pckg.ConfirmationListPreference
android:key="#string/key_pref_app_language"
android:title="#string/pref_app_language_title"
android:entries="#array/pref_app_language_list_titles"
android:entryValues="#array/pref_app_language_list_values"
android:defaultValue="0"
android:negativeButtonText="#string/button_title_cancel"
android:positiveButtonText="#string/button_title_ok"
/>
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.
Ok, I know there have been a lot of questions about SharedPreferences in Android asked before, and I did manage to get quite far, but since I'm kinda new to SharedPreferences I don't know the last few steps to get it to work.
In my MainActivity I have the following:
public class MainActivity extends ActionBarActivity
{
...
// Public static MainActivity so we can use findViewById from MyPrefsActivity
public static MainActivity mActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mActivity = this;
}
...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch(id){
case R.id.action_settings:
startActivity(new Intent(this, MyPrefsActivity.class));
return true;
}
return false;
}
}
And this is MyPrefsActivity.java:
package com.example.checkboxoptionsv2;
import android.annotation.TargetApi;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.ImageButton;
public class MyPrefsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener
{
private static int prefs = R.xml.settings;
private ImageButton cbButton, spinnerButton, popupButton;
private final String LIST_PREFERENCE = "prefCheckboxOption";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
getClass().getMethod("getFragmentManager");
AddResourceApi11AndGreater();
}
catch(NoSuchMethodException e){ // Android API < 11
AddResourceApiLessThan11();
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
preferences.registerOnSharedPreferenceChangeListener(this);
* ListPreference listPreference = (ListPreference) findPreference(LIST_PREFERENCE);
if(listPreference.getValue() == null)
listPreference.setValue("0");
cbButton = (ImageButton) MainActivity.mActivity.findViewById(R.id.ibtnCheckbox);
spinnerButton = (ImageButton) MainActivity.mActivity.findViewById(R.id.ibtnSpinner);
popupButton = (ImageButton) MainActivity.mActivity.findViewById(R.id.ibtnPopup);
setChosenPreference(0);
}
private void setChosenPreference(int chosen_value){
// First put all Visibilities on GONE
cbButton.setVisibility(View.GONE);
spinnerButton.setVisibility(View.GONE);
popupButton.setVisibility(View.GONE);
// Then turn the chosen on VISIBLE again
switch(chosen_value){
case 0: // Multi-Click CheckBox
default:
cbButton.setVisibility(View.VISIBLE);
break;
case 1: // Dropdown CheckBox
spinnerButton.setVisibility(View.VISIBLE);
break;
case 2: // Pop-up CheckBox
popupButton.setVisibility(View.VISIBLE);
break;
}
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals(LIST_PREFERENCE)){
ListPreference listPreference = (ListPreference) findPreference(key); // LIST_PREFERENCE
listPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
int chosen_option = Integer.valueOf((String) newValue);
setChosenPreference(chosen_option);
return false;
}
});
}
else{
// Other settings
}
}
#SuppressWarnings("deprecation")
protected void AddResourceApiLessThan11(){
addPreferencesFromResource(prefs);
}
#TargetApi(11)
protected void AddResourceApi11AndGreater(){
* MyPreferenceFragment pf = new MyPreferenceFragment();
getFragmentManager().beginTransaction().replace(android.R.id.content, pf).commit();
}
#TargetApi(11)
public static class MyPreferenceFragment extends PreferenceFragment{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
* addPreferencesFromResource(MyPrefsActivity.prefs); // outer class
// private members seem to be visible for inner class, and
// making it static made things so much easier
}
}
}
And the settings.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory android:title="#string/checkbox_options_title" >
<ListPreference
android:key="prefCheckboxOption"
android:title="#string/pref_checkbox_option"
android:summary="#string/checkbox_options_summary"
android:entries="#array/checkbox_options"
android:entryValues="#array/checkbox_option_values" />
</PreferenceCategory>
</PreferenceScreen>
and arrays.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="checkbox_options">
<item>CheckBox as Multi-Click</item>
<item>CheckBox as Dropdown</item>
<item>CheckBox as Pop-up</item>
</string-array>
<string-array name="checkbox_option_values">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
</resources>
(Of course I've also included the MyPrefsActivity in the AndroidManifest.xml)
My goal is to make one of the three checkbox-option (found in the setChosenPreference method) VISIBLE, and the other two GONE, based on the preference selected in the ListPreference.
Right now the Listpreference in both the onCreate() method and onSharedPreferenceChanged() is null and giving a NullPointerException. So I set some breakpoints (see the three " * ") and the reason they are null is because the third " * " (in the static class PF) isn't called.
The addPreferencesFromResources should be called before using findPreference, otherwise it will return null. Does anyone know why during debugging I do get to the second " * " in the AddResourceApi11AndGreater() method, but I'm not getting to the third one in the MyPreferenceFragment-class onCreate method() ?.. the onCreate isn't called at all..
Also, does the rest of my code seems ok(-ish) or should I change something in order to make it work as I intended?
Thanks in advance for the responses.
TL;DR: MyPreferenceFragment instantion is created successfully, but it's #Override onCreate method is never called.
EDIT 1: Ok, I did found the problem: When I added addPreferencesFromResource(prefs) in the activity's onCreate method as a debug-test, I found out that the MyPreferenceFragment-class is indeed being initialized, then it finishes the activity's onCreate method (which would have failed at findPreference() if I didn't added the addPreferencesFromResource(prefs) test-line), and only after the activity's onCreate method is completely finished, it goes to the MyPreferenceFragment's onCreate method.
Is there a way to let the PreferenceFrament's onCreate method go first, while in the middle of the activity's onCreate method, so after AddResourceApi11AndGreater() but before findPreference(LIST_PREFERENCE)?
Move your logic to PF, don't do things in PreferenceActivity.
There are also changes in the way of listening to the preferences changes. Check the code.
public class MyPrefsActivity extends PreferenceActivity {
private static int prefs = R.xml.settings;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
getClass().getMethod("getFragmentManager");
AddResourceApi11AndGreater();
}
catch(NoSuchMethodException e){ // Android API < 11
AddResourceApiLessThan11();
}
}
#SuppressWarnings("deprecation")
protected void AddResourceApiLessThan11(){
addPreferencesFromResource(prefs);
}
#TargetApi(11)
protected void AddResourceApi11AndGreater(){
getFragmentManager().beginTransaction().replace(android.R.id.content,
new PF()).commit();
}
#TargetApi(11)
public static class PF extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private ImageButton cbButton, spinnerButton, popupButton;
private final String LIST_PREFERENCE = "prefCheckboxOption";
#Override
public void onCreate(final Bundle savedInstanceState){
super.onCreate(savedInstanceState);
addPreferencesFromResource(MyPrefsActivity.prefs); // outer class
// private members seem to be visible for inner class, and
// making it static made things so much easier
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
preferences.registerOnSharedPreferenceChangeListener(this);
ListPreference listPreference = (ListPreference) findPreference(LIST_PREFERENCE);
if(listPreference.getValue() == null)
listPreference.setValue("0");
cbButton = (ImageButton) MainActivity.mActivity.findViewById(R.id.ibtnCheckbox);
spinnerButton = (ImageButton) MainActivity.mActivity.findViewById(R.id.ibtnSpinner);
popupButton = (ImageButton) MainActivity.mActivity.findViewById(R.id.ibtnPopup);
setChosenPreference(Integer.valueOf(preferences.getString(LIST_PREFERENCE, "0")));
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
int chosen_option = Integer.valueOf(sharedPreferences.getString(key, "0"));
setChosenPreference(chosen_option);
}
private void setChosenPreference(int chosen_value){
// First put all Visibilities on GONE
cbButton.setVisibility(View.GONE);
spinnerButton.setVisibility(View.GONE);
popupButton.setVisibility(View.GONE);
// Then turn the chosen on VISIBLE again
switch(chosen_value){
case 0: // Multi-Click CheckBox
default:
cbButton.setVisibility(View.VISIBLE);
break;
case 1: // Dropdown CheckBox
spinnerButton.setVisibility(View.VISIBLE);
break;
case 2: // Pop-up CheckBox
popupButton.setVisibility(View.VISIBLE);
break;
}
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
i finally figured out where to find most of this.
but now i need to know how to test one part of this program for a username.
My goal is if the user doesn't put anything in the program then don't allow anything to continue.
This is a big app. I have like 3 layout files and 3 java files.
Any help would be good if you need me to send the file i can.
package edu.jones.demogamestartarrayadaptor;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
//import android.view.KeyEvent;
import android.view.View;
//import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
//import android.widget.Toast;
public class GameControlMainActivity extends ListActivity
{
//Class-wide variables for data passed/returned
private String userName = "";
//Use an int for gameLevel,naturally...but, this requires
//use of various methods to convert to String and back!
private int gameLevel = 1;
private EditText nameEntryET;
private TextView gameLevelAnnouncerTV;
private TextView gameLevelTV;
Button doneButton;
//This TV prompts user to enter name in the EditText
//Then, it is made invisible
private TextView namePromptTV;
//These two start out invisible and then show the name
private TextView nameSetTV;
private TextView nameEntTV;
//Array of choices for user
static final String[] CHOICES = new String[]
{
"Read directions",
"Play Game",
"Quit"
};
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Set up View ids
nameEntryET = (EditText)findViewById(R.id.enter_nameET);
gameLevelAnnouncerTV = (TextView) findViewById(R.id.game_level_announcer_TV);
gameLevelTV = (TextView) findViewById(R.id.game_level_TV);
//Set the game level in the TextView
gameLevelTV.setText(Integer.toString(gameLevel));
namePromptTV = (TextView)findViewById(R.id.name_prompt_tv);
nameSetTV = (TextView)findViewById(R.id.name_set_tv);
nameEntTV = (TextView)findViewById(R.id.name_entered_tv);
//Set Done button listener to get user's name
doneButton = (Button) findViewById(R.id.doneBtn);
setDoneButtonListener();
//Set up ArrayAdaptor for the options
setListAdapter(new ArrayAdapter<String>
(this, android.R.layout.simple_list_item_1, CHOICES));
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
getListView().setTextFilterEnabled(true);
//Set up the listener for user clicks on the list
setListClickListener();
//this toast is for when it opens
Toast.makeText(this, "yo whats up", Toast.LENGTH_SHORT).show();
}//END onCreate
private void setDoneButtonListener()
{
doneButton.setOnClickListener
(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//Get user's name when button is clicked
//Call method to set text and hide button
setUserNameAndHideButton();
}
}
);//END setOnClickListener
}//END setDoneButtonListener
//Sets up username in its TextView, and game level Views,
//then hides the other Views & button
private void setUserNameAndHideButton()
{
userName = nameEntryET.getText().toString();
doneButton.setVisibility(View.GONE);
Toast.makeText(this, "Your name has been entered", Toast.LENGTH_SHORT).show();
//After getting the input, hide the EditText
//VISIBLE(0), INVISIBLE(4) or GONE(8)
nameEntryET.setVisibility(View.INVISIBLE);
namePromptTV.setVisibility(View.GONE);
nameEntTV.setText(userName);
nameSetTV.setVisibility(View.VISIBLE);
nameEntTV.setVisibility(View.VISIBLE);
gameLevelAnnouncerTV.setVisibility(View.VISIBLE);
gameLevelTV.setVisibility(View.VISIBLE);
}//END setUserNameAndHideButton
//Set up the listener for the ListView to interpret user clicks
private void setListClickListener()
{
//Set up the click listener for the options
getListView().setOnItemClickListener
(
new OnItemClickListener()
{
//#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
switch(arg2)
{
case 0: launchDirectionsPage();
break;
case 1: startGame();
break;
case 2: finish();
break;
default: break;
}
}
}//END OnItemClickListener
);//END setOnItemClickListener
}//END setListClickListener
//Launch a simple activity to show a scroll view of directions
protected void launchDirectionsPage()
{
//Set up Intent
Intent launchDirections = new Intent(this, DirectionsPageActivity.class);
startActivity(launchDirections);
}//END launchDirectionsPage
//Launch the activity that allows user to input new game value
//Upon return the onActivityResult method is called
protected void startGame()
{
//Set up Intent to launch other activity: PlayGame
Intent launchGame = new Intent(this, PlayGameActivity.class);
//Info added to the Intent's Bundle to pass to PlayGameActivity
launchGame.putExtra("bdl_username", userName);
launchGame.putExtra("bdl_gamelevel", gameLevel);
startActivityForResult(launchGame, 0);
}//END startGame
//This method will be called when the startGame activity terminates
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == 0 && resultCode == RESULT_OK)
{
//Reset the views to possibly updated info returned in the Intent
//First, access the Bundle's values
userName = data.getExtras().getString("bdl_returnUserName");
gameLevel = data.getExtras().getInt("bdl_returnGameLevel");
//Update the user name & game level with values from other activity
nameEntTV.setText(userName);
gameLevelTV.setText(Integer.toString(gameLevel));
}
}//END onActivityResult
#Override
protected void onSaveInstanceState (Bundle outState)
{
super.onSaveInstanceState(outState);
//Add the username and game level to the Bundle
outState.putString("bdl_savedusername", userName);
outState.putInt("bdl_savedgamelevel", gameLevel);
}//END onSaveInstanceState
#Override
public void onRestoreInstanceState (Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
//Restore the username and game level from the Bundle
userName = savedInstanceState.getString("bdl_savedusername");
gameLevel = savedInstanceState.getInt("bdl_savedgamelevel");
}//END onRestoreInstanceState
}//END GameControlMainActivity
If you are asking to stop if the username is not entered, just do this:
private void setDoneButtonListener()
{
doneButton.setOnClickListener
(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
if (nameEntryET.getText().toString().equals("")) {
Toast.makeText(this, "Enter a username", Toast.LENGTH_LONG).show();
} else {
//Get user's name when button is clicked
//Call method to set text and hide button
setUserNameAndHideButton();
}
}
}
);//END setOnClickListener
}//END setDoneButtonListener
if nameEntryET does not have a value entered, nameEntryET.getText().toString() will return an empty string.
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;
}
});
}
}