Как создать одно из предпочтений с помощью EditTextPreference и Togglebutton?
То, что я пытаюсь реализовать, - это в основном и точная копия изображения ниже (предпочтения, которые я построил в квадрате). При нажатии клавиши слева от предпочтения следует открыть диалог. Нажатие кнопки toggle отключит/включит все, что я установлю в этом предпочтении.
Я пробовал уже несколько часов, и я пришел с пустыми руками. Как реализовать это в PreferenceActivity?
![Preference]()
EDIT: Кажется, люди не понимают мой вопрос. Очень важно выяснить, как решить мою проблему с помощью PreferenceActivity. НЕ РАБОТАЕТ. Мне все равно, нужно ли мне это делать в XML или программно. Просто воздержитесь от предоставления мне ответов, которые я не могу использовать в чем-то подобном.
EDIT 2: Добавлена щедрость - мне действительно нужен ответ на этот
Ответы
Ответ 1
Чёрный человек, мне нравится твоя идея: -)
Это так же, как и ответ @MH, но более краткий.
Я тестировал с ToggleButton
, а не Switch
.
package android.dumdum;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ToggleButton;
public class TogglePreference extends Preference {
public TogglePreference(Context context) {
super(context);
}
public TogglePreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TogglePreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public View getView(View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = new LinearLayout(getContext());
((LinearLayout) convertView)
.setOrientation(LinearLayout.HORIZONTAL);
TextView txtInfo = new TextView(getContext());
txtInfo.setText("Test");
((LinearLayout) convertView).addView(txtInfo,
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT, 1));
ToggleButton btn = new ToggleButton(getContext());
((LinearLayout) convertView).addView(btn);
}
return convertView;
}
}
И preferences.xml
:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory android:title="Test custom preferences" >
<android.dumdum.EncryptorEditTextPreference />
<android.dumdum.TogglePreference />
</PreferenceCategory>
</PreferenceScreen>
EncryptorEditTextPreference
не связан с вашим вопросом, но использует ту же технику (расширение EditTextPreference
).
Ответ 2
Только примечание: это будет длинный ответ, но я намерен предоставить вам хороший ответ, который вы могли бы буквально скопировать и вставить для начала.
На самом деле это не так сложно сделать. Лучшей отправной точкой будет поиск реализации SwichPreference
в ICS. Вы увидите, что это довольно просто, причем большая часть работы выполняется суперклассом TwoStatePreference
, который, в свою очередь, также доступен только ICS. К счастью, вы можете почти буквально скопировать-вставить (см. Весь путь вниз в этом ответе) этот класс и создать свой собственный TogglePreference
(пусть он называет его для ясности), используя реализацию SwitchPreference
как руководство.
То, что вы получите, сделайте это, как показано ниже. Я добавил некоторые объяснения к каждому методу, чтобы ограничить мое письмо здесь.
TogglePreference.java
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
, используя соответствующие идентификаторы в пространстве имен Android. Таким образом, нам не о чем беспокоиться. Обратите внимание, что я уверен, что параметр значка не был добавлен до Honeycomb, поэтому вы можете просто добавить его в качестве настраиваемого атрибута в TogglePreference
и вручную установить его так, чтобы он всегда был там. Просто напишите мне комментарий, если вам нужны какие-то конкретные указатели для этого подхода.
В любом случае, очевидно, вы можете модифицировать макет в любой степени и применять стиль по своему вкусу. Например, чтобы иметь ToggleButton
mimic a 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>
Затем вы можете использовать TogglePreference
так же, как и любой другой Preference
в PreferenceActivity
. Подключив слушателя, вы можете делать все, что угодно, когда пользователь выбирает предпочтение, в то время как нажатие фактического 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
. Вы можете предоставить все обычные атрибуты в пространстве имен Android. Кроме того, вы можете также объявить некоторые пользовательские атрибуты для использования встроенных функций TwoStatePreference
для обработки текстов summaryOn
и summaryOff
.
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>
Наконец, backported класс TwoStatePreference от ICS. Это вряд ли отличается от оригинала, для которого вы можете найти источник 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 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 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];
}
};
}
}
![TogglePreference without any fancy styling applied]()
Ответ 3
Не уверен, что это кнопка переключения, но если это так, вы можете просто сказать android: textOn или android: textoff на .xml. Если он находится в java-части, это, вероятно, просто что-то вроде setTextOnNot определенно, если это кнопка переключения, но если это вы можете просто сказать android: textOn или android: textoff на .xml. Если в java-части это, вероятно, просто что-то вроде toggleButton.setChecked.
Ответ 4
Я не уверен, в какую проблему вы столкнулись, я просто создал фиктивный вид, как то, о чем вы говорите, и я не вижу проблемы.
<TableRow
android:id="@+id/tableRow1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Switch
android:id="@+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Switch" />
</TableRow>
Ответ 5
Этот XML-код можно использовать в файле pref xml
<PreferenceCategory>
<EditTextPreference
android:key="myEditText"
android:title="Hi"
android:inputType="Mine"></EditTextPreference>
</PreferenceCategory>
и вы можете использовать флажок вместо togglebutton с этим кодом:
<CheckBoxPreference
android:key="testmode"
android:title="@string/test_mode"></CheckBoxPreference>
Если вы не хотите использовать флажок, вы можете использовать этот код:
Ответ 6
Просто используйте SwitchPreference
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<SwitchPreference
android:key="test"
android:title="This is test toggle switch" />
</PreferenceScreen>
выглядит так (просто образец из моего приложения, не беспокоитесь о других префайлах)
![enter image description here]()