बस एक नोट अग्रिम: यह एक लंबी जवाब का एक सा होने जा रहा है, लेकिन मेरा इरादा प्रदान करना है आप एक अच्छा जवाब देने के साथ कि आप सचमुच शुरू करने के लिए कॉपी और पेस्ट कर सकते हैं।
यह वास्तव में पूरा करने में बहुत मुश्किल नहीं है। आपका सबसे अच्छा प्रारंभिक बिंदु आईसीएस पर SwichPreference
के कार्यान्वयन को देखना होगा। आप देखेंगे कि यह काफी सरल है, अधिकांश काम TwoStatePreference
सुपरक्लास द्वारा किया जा रहा है, जो इसकी बारी पर केवल आईसीएस उपलब्ध है। सौभाग्य से, आप लगभग SwitchPreference
कार्यान्वयन के रूप में कार्यान्वयन के उपयोग से, उस वर्ग के लगभग TogglePreference
(चलिए इसे स्पष्टता के लिए कहते हैं) के आधार पर लगभग सचमुच कॉपी-पेस्ट (इस उत्तर में सभी तरह से नीचे देखें) बना सकते हैं।
आपको ऐसा करने से क्या मिलेगा, नीचे कुछ ऐसा है। मैंने प्रत्येक विधि को कुछ स्पष्टीकरण जोड़ा ताकि मैं यहां अपने लेखन को सीमित कर सकूं।
TogglePreference।जावा
package mh.so.pref;
import mh.so.R;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ToggleButton;
/**
* A {@link Preference} that provides a two-state toggleable option.
* <p>
* This preference will store a boolean into the SharedPreferences.
*/
public class TogglePreference extends TwoStatePreference {
private final Listener mListener = new Listener();
private ExternalListener mExternalListener;
/**
* Construct a new TogglePreference with the given style options.
*
* @param context The Context that will style this preference
* @param attrs Style attributes that differ from the default
* @param defStyle Theme attribute defining the default style options
*/
public TogglePreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Construct a new TogglePreference with the given style options.
*
* @param context The Context that will style this preference
* @param attrs Style attributes that differ from the default
*/
public TogglePreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Construct a new TogglePreference with default style options.
*
* @param context The Context that will style this preference
*/
public TogglePreference(Context context) {
this(context, null);
}
/** Inflates a custom layout for this preference, taking advantage of views with ids that are already
* being used in the Preference base class.
*/
@Override protected View onCreateView(ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.toggle_preference_layout, parent, false);
}
/** Since the Preference base class handles the icon and summary (or summaryOn and summaryOff in TwoStatePreference)
* we only need to handle the ToggleButton here. Simply get it from the previously created layout, set the data
* against it and hook up a listener to handle user interaction with the button.
*/
@Override protected void onBindView(View view) {
super.onBindView(view);
ToggleButton toggleButton = (ToggleButton) view.findViewById(R.id.toggle_togglebutton);
toggleButton.setChecked(isChecked());
toggleButton.setOnCheckedChangeListener(mListener);
}
/** This gets called when the preference (as a whole) is selected by the user. The TwoStatePreference
* implementation changes the actual state of this preference, which we don't want, since we're handling
* preference clicks with our 'external' listener. Hence, don't call super.onClick(), but the onPreferenceClick
* of our listener. */
@Override protected void onClick() {
if (mExternalListener != null) mExternalListener.onPreferenceClick();
}
/** Simple interface that defines an external listener that can be notified when the preference has been
* been clicked. This may be useful e.g. to navigate to a new activity from your PreferenceActivity, or
* display a dialog. */
public static interface ExternalListener {
void onPreferenceClick();
}
/** Sets an external listener for this preference*/
public void setExternalListener(ExternalListener listener) {
mExternalListener = listener;
}
/** Listener to update the boolean flag that gets stored into the Shared Preferences */
private class Listener implements CompoundButton.OnCheckedChangeListener {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!callChangeListener(isChecked)) {
// Listener didn't like it, change it back.
// CompoundButton will make sure we don't recurse.
buttonView.setChecked(!isChecked);
return;
}
TogglePreference.this.setChecked(isChecked);
}
}
}
इस उदाहरण के लिए लेआउट फ़ाइल बस एक उस में LinearLayout
तीन के साथ तत्वों, सबसे दिलचस्प एक होने ToggleButton
के साथ है। ImageView
और TextView
Preference
बेस क्लास का लाभ उठाएं जो एंड्रॉइड नेमस्पेस में उपयुक्त आईडी का उपयोग करके पहले से ही करता है। इस तरह, हमें उन लोगों के बारे में चिंता करने की ज़रूरत नहीं है। ध्यान दें कि मुझे पूरा यकीन है कि आइकन विकल्प हनीकॉम तक नहीं जोड़ा गया था, इसलिए आप इसे TogglePreference
पर एक कस्टम विशेषता के रूप में जोड़ना चाहते हैं और इसे मैन्युअल रूप से सेट करना चाहते हैं ताकि यह हमेशा वहां रहे। अगर आपको इस दृष्टिकोण के लिए और अधिक ठोस पॉइंटर्स की आवश्यकता है तो बस मुझे एक टिप्पणी फ्लिक करें।
वैसे भी, आप किसी भी विस्तार के लिए लेआउट को संशोधित कर सकते हैं, और अपनी पसंद के अनुसार स्टाइल लागू कर सकते हैं। उदाहरण के लिए, ToggleButton
Switch
नकल करने के लिए, आप पृष्ठभूमि को किसी अन्य StateListDrawable
पर बदल सकते हैं और/या बदल सकते हैं या पूरी तरह से चालू/बंद टेक्स्ट से छुटकारा पा सकते हैं।
toggle_preference_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight" >
<ImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:focusable="false"
android:focusableInTouchMode="false" />
<TextView
android:id="@android:id/summary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:focusable="false"
android:focusableInTouchMode="false"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ToggleButton
android:id="@+id/toggle_togglebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:focusable="false"
android:focusableInTouchMode="false" />
</LinearLayout>
फिर आप सिर्फ अपने PreferenceActivity
में किसी भी अन्य की तरह Preference
TogglePreference
उपयोग कर सकते हैं। श्रोता को जोड़कर, जब आप उपयोगकर्ता को वरीयता चुनते हैं तो आप कुछ भी कर सकते हैं, जबकि एक ही समय में वास्तविक ToggleButton
पर क्लिक करके SharedPreferences
में बूलियन मान टॉगल करेगा।
DemoPreferenceActivity.java
package mh.so.pref;
import mh.so.R;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.widget.Toast;
public class DemoPreferenceActivity extends PreferenceActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
TogglePreference toggle = (TogglePreference) findPreference("toggle_preference");
toggle.setExternalListener(new TogglePreference.ExternalListener() {
@Override public void onPreferenceClick() {
Toast.makeText(DemoPreferenceActivity.this, "You clicked the preference without changing its value", Toast.LENGTH_LONG).show();
}
});
}
}
Prefs.xml ज्यादा कुछ नहीं लेकिन TogglePreference
ऊपर की एक एकल परिभाषा है। आप एंड्रॉइड के नामस्थान में सभी सामान्य विशेषताओं की आपूर्ति कर सकते हैं। वैकल्पिक रूप से आप summaryOn
और summaryOff
ग्रंथों से निपटने के लिए TwoStatePreference
की अंतर्निहित कार्यक्षमता का शोषण करने के लिए कुछ कस्टम विशेषताओं की घोषणा भी कर सकते हैं।
Prefs.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory android:title="Toggle preferences" >
<mh.so.pref.TogglePreference xmlns:app="http://schemas.android.com/apk/res/mh.so"
android:key="toggle_preference"
android:summary="Summary"
android:icon="@drawable/icon" />
</PreferenceCategory>
</PreferenceScreen>
अंत में, आईसीएस से बैकपोर्टेड TwoStatePreference वर्ग। यह मूल रूप से मूल से अलग नहीं है, जिसके लिए आप स्रोत overhere पा सकते हैं।
package mh.so.pref;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
/**
* Common base class for preferences that have two selectable states, persist a
* boolean value in SharedPreferences, and may have dependent preferences that are
* enabled/disabled based on the current state.
*/
public abstract class TwoStatePreference extends Preference {
private CharSequence mSummaryOn;
private CharSequence mSummaryOff;
private boolean mChecked;
private boolean mDisableDependentsState;
public TwoStatePreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public TwoStatePreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TwoStatePreference(Context context) {
this(context, null);
}
@Override
protected void onClick() {
super.onClick();
boolean newValue = !isChecked();
if (!callChangeListener(newValue)) {
return;
}
setChecked(newValue);
}
/**
* Sets the checked state and saves it to the {@link SharedPreferences}.
*
* @param checked The checked state.
*/
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
persistBoolean(checked);
notifyDependencyChange(shouldDisableDependents());
notifyChanged();
}
}
/**
* Returns the checked state.
*
* @return The checked state.
*/
public boolean isChecked() {
return mChecked;
}
@Override
public boolean shouldDisableDependents() {
boolean shouldDisable = mDisableDependentsState ? mChecked : !mChecked;
return shouldDisable || super.shouldDisableDependents();
}
/**
* Sets the summary to be shown when checked.
*
* @param summary The summary to be shown when checked.
*/
public void setSummaryOn(CharSequence summary) {
mSummaryOn = summary;
if (isChecked()) {
notifyChanged();
}
}
/**
* @see #setSummaryOn(CharSequence)
* @param summaryResId The summary as a resource.
*/
public void setSummaryOn(int summaryResId) {
setSummaryOn(getContext().getString(summaryResId));
}
/**
* Returns the summary to be shown when checked.
* @return The summary.
*/
public CharSequence getSummaryOn() {
return mSummaryOn;
}
/**
* Sets the summary to be shown when unchecked.
*
* @param summary The summary to be shown when unchecked.
*/
public void setSummaryOff(CharSequence summary) {
mSummaryOff = summary;
if (!isChecked()) {
notifyChanged();
}
}
/**
* @see #setSummaryOff(CharSequence)
* @param summaryResId The summary as a resource.
*/
public void setSummaryOff(int summaryResId) {
setSummaryOff(getContext().getString(summaryResId));
}
/**
* Returns the summary to be shown when unchecked.
* @return The summary.
*/
public CharSequence getSummaryOff() {
return mSummaryOff;
}
/**
* Returns whether dependents are disabled when this preference is on ({@code true})
* or when this preference is off ({@code false}).
*
* @return Whether dependents are disabled when this preference is on ({@code true})
* or when this preference is off ({@code false}).
*/
public boolean getDisableDependentsState() {
return mDisableDependentsState;
}
/**
* Sets whether dependents are disabled when this preference is on ({@code true})
* or when this preference is off ({@code false}).
*
* @param disableDependentsState The preference state that should disable dependents.
*/
public void setDisableDependentsState(boolean disableDependentsState) {
mDisableDependentsState = disableDependentsState;
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getBoolean(index, false);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setChecked(restoreValue ? getPersistedBoolean(mChecked)
: (Boolean) defaultValue);
}
/**
* Sync a summary view contained within view's subhierarchy with the correct summary text.
* @param view View where a summary should be located
*/
void syncSummaryView(View view) {
// Sync the summary view
TextView summaryView = (TextView) view.findViewById(android.R.id.summary);
if (summaryView != null) {
boolean useDefaultSummary = true;
if (mChecked && mSummaryOn != null) {
summaryView.setText(mSummaryOn);
useDefaultSummary = false;
} else if (!mChecked && mSummaryOff != null) {
summaryView.setText(mSummaryOff);
useDefaultSummary = false;
}
if (useDefaultSummary) {
final CharSequence summary = getSummary();
if (summary != null) {
summaryView.setText(summary);
useDefaultSummary = false;
}
}
int newVisibility = View.GONE;
if (!useDefaultSummary) {
// Someone has written to it
newVisibility = View.VISIBLE;
}
if (newVisibility != summaryView.getVisibility()) {
summaryView.setVisibility(newVisibility);
}
}
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.checked = isChecked();
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setChecked(myState.checked);
}
static class SavedState extends BaseSavedState {
boolean checked;
public SavedState(Parcel source) {
super(source);
checked = source.readInt() == 1;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(checked ? 1 : 0);
}
public SavedState(Parcelable superState) {
super(superState);
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}

खुशी है कि आप इस सूत्र शुरू कर दिया था! :) – Roylee