2012-03-16 67 views
11

我想要实现的是基本上和下面的图像(我平方的偏好)的确切副本。按首选项左侧的任何内容都会打开一个对话框。按下切换按钮将禁用/启用我在此首选项中设置的任何内容。如何使用EditTextPreference和Togglebutton创建一个首选项?

我一直在尝试几个小时,我已经空手而归了。我如何在PreferenceActivity中实现这一点?

Preference

编辑:看来人都误解我的问题。使用PreferenceActivity来弄清楚如何解决我的问题是非常重要的。不是活动。我不在乎是否需要用XML或编程方式来完成它。只是请不要向我提供我无法在某个类似内容中使用的答案。

编辑2:添加了赏金 - 我真的需要一个答案

+0

很高兴你会发起的主题! :) – Roylee 2013-05-12 09:27:00

回答

17

地狱的人,我喜欢你的想法:-)

这只是一样@ 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)相同的技术。

0

不能肯定,如果这是一个切换按钮,但如果它是你可以说安卓纹元或Android:上textoff。 XML。如果它在Java部件上,它可能只是像setTextOn那样确定如果这是一个切换按钮,但如果它是你可以在.xml上说android:textOn或android:textoff。如果它在java部分,它可能只是像toggleButton.setChecked。

0

我不知道你碰到了,我刚刚创建像你指的是什么的虚拟视图什么问题,我看不出有任何问题

<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> 
+0

我遇到的问题是我在PreferenceActivity中工作的事实。不是活动。 PreferenceActivity的工作方式不同,每个“行”在XML中由Preferencetag定义,如:。我的问题在于结合这两种偏好。不只是在表格中创建一个开关和一个textview。 – CodePrimate 2012-03-19 07:58:56

0

您可以在PREF使用XML代码xml文件

<PreferenceCategory> 
     <EditTextPreference 
      android:key="myEditText" 
      android:title="Hi" 
      android:inputType="Mine"></EditTextPreference> 
    </PreferenceCategory> 

,你可以使用复选框切换按钮,而不是与此代码:

<CheckBoxPreference 
     android:key="testmode" 
     android:title="@string/test_mode"></CheckBoxPreference> 

如果你不希望使用复选框,您可以使用此代码:

+1

谢谢,你的代码相当不错:-) – 2012-03-24 09:57:17

8

刚一说明前期:这将是一个有点长的答案,但我的本意是提供你有一个很好的答案,你可以从字面上复制和粘贴来开始。

这实际上并不太难完成。你最好的出发点是在ICS上查找SwichPreference的实现。你会发现它非常简单,大部分工作都是由一个TwoStatePreference超类完成的,而超类又是唯一可用的ICS。幸运的是,使用SwitchPreference实现作为指导,几乎可以从字面上复制粘贴(在此答案中一路查看),然后构建您自己的TogglePreference(为了清楚起见,我们可以称它为“顶层”)。

通过这样做你会得到什么,如下所示。我为每种方法添加了一些解释,以便在这里限制我的写作。

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有三个要素,其中最有趣的一个是ToggleButtonImageViewTextView利用基本类已经完成的工作,方法是在Android命名空间中使用相应的ID。这样,我们不必担心这些。请注意,我很确定在Honeycomb之前不会添加图标选项,因此您可能只想将其添加为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> 

然后可以使用TogglePreference就像你PreferenceActivity任何其他Preference。通过连接听众,当用户选择首选项时,可以做任何你喜欢的事情,同时点击实际的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的内置功能来处理summaryOnsummaryOff文本。

的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> 

最后,从ICS中导出的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]; 
      } 
     }; 
    } 
} 

TogglePreference without any fancy styling applied

0

只需使用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

相关问题