Implementing long-clickable preferences
The built-in Preference class has a method to receive clicks, onClick, but no method to receive long clicks. In my current project, I actually have a need for this, and found a way to implement it.
PreferenceActivity is actually a ListActivity, with a special adapter behind the scenes. The usual (not long) clicks are processed by using the usual ListView mechanism, setOnItemClickListener. The code to set this up is in PreferenceScreen:
public final class PreferenceScreen extends PreferenceGroup implements AdapterView.OnItemClickListener.... {
public void bind(ListView listView) {
listView.setOnItemClickListener(this);
listView.setAdapter(getRootAdapter());
onAttachedToActivity();
}
public void onItemClick(AdapterView parent, View view, int position, long id) {
Object item = getRootAdapter().getItem(position);
if (!(item instanceof Preference)) return;
final Preference preference = (Preference) item;
preference.performClick(this);
}
}
It would be really easy to subclass PreferenceScreen and override bind to add a long-item-click listener to the list view, except this class is final. Because of this, I ended up adding the following code into my PreferenceActivity subclass:
public class BlahBlahActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.account_options_prefs);
ListView listView = getListView();
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
ListView listView = (ListView) parent;
ListAdapter listAdapter = listView.getAdapter();
Object obj = listAdapter.getItem(position);
if (obj != null && obj instanceof View.OnLongClickListener) {
View.OnLongClickListener longListener = (View.OnLongClickListener) obj;
return longListener.onLongClick(view);
}
return false;
}
});
}
}
Now I can have a Preference subclass that implements View.OnLongClickListener, which is automatically invoked for long clicks:
public class BlahBlahPreference extends CheckBoxPreference implements View.OnLongClickListener {
@Override
public boolean onLongClick(View v) {
// Do something for long click
return true;
}
}
The second code block is what you put into your PreferenceActivity subclass. It’s the “infrastructure”. It checks for whether a particular preference is long-clickable by using instanceof operator.
Therefore, a preference that wishes to receive long clicks is expected to have “implements View.OnLongClickListener” in its class declaration.
So:
Make your own preference class that “extends CheckBoxPreference implements View.OnLongClickListener” – that’s the third code block above.
Eclipse will require that you implement:
@Override public boolean onLongClick(View v) { // Do something for long click return true; }in your preference class. This is where you can respond to long clicks.
Then use this preference instead of a “regular” CheckBoxPreference in your preference xml file, by specifying its fully qualified class:
<PreferenceScreen ...> <my.app.package.name.MyLongClickableCheckBoxPreference android:key="..." android:title="Long click me" ........... /> </PreferenceScreen>AWESOME!!! Thanks for your help!
Do you have a working example of the code that I could see? I don’t quite understand how to implement it.
The see the second and third code blocks above, in the body of the post.
I don’t see how the third code block is related to the second code block.
I would like to use a checkboxPreference so I would do the following?
BlahBlahPreference myPreference;
// get initial settings
addPreferencesFromResource(R.layout.blahPrefs);
myPreference = (CheckBoxPreference) findPreference(“blah”);
Right now I’m using
myPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference arg0, Object arg1)
{ Log.d(TAG,”PreferenceChange”); });
}
How do I use your Long click code?
myPreference.setOnItemLongClickListener(new OnItemLongClickListener() {
//@Override
public boolean onItemLongClick(AdapterView parent, View view, int pos, final long listId) {
….
}
I can not cast myPreference to ListView…..
Thank you very much for your article. But how to retrieve the Preference-object within onItemLongClick?
Or: How to retrieve this object from id or position?
public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
Preference pref = ?
}
Alexander,
It’s shown above:
Get the preference object with “Object obj = listAdapter.getItem(position);”, then check “instanceof View.OnLongClickListener”.
Yes, you are right. It works:
@Override
public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
ListView listView = (ListView) parent;
ListAdapter listAdapter = listView.getAdapter();
Object obj = listAdapter.getItem(position);
if (obj != null && obj instanceof View.OnLongClickListener) {
View.OnLongClickListener longListener = (View.OnLongClickListener) obj;
return longListener.onLongClick(view);
} else {
Preference pref = (Preference) obj;
// do something with pref …
}
return true;
}
Worked like a charm, thanks.