2012-04-19 35 views
8

如何使像Android本機設置應用程序的SwitchReference的設置導航?android:如何使設置導航像本機設置的應用程序

凡當u點擊無線網絡區域(未在交換機上),它會瀏覽到一個新的屏幕:

Click on WiFi

我的應用程序只有開關從ON當我改變到OFF,反之亦然甚至沒有點擊開關。

我使用PreferenceFragment和xml作爲屏幕。我的偏好是遵循Android PreferenceFragment documentation的例子。我在ICS 4.0 API 14上開發我的應用程序。

任何人都知道如何做到這一點?

編輯:

我的XML是這樣的:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > 

    <PreferenceCategory 
     android:layout="@layout/preference_category" 
     android:title="User Settings" > 
     <SwitchPreference 
      android:key="pref_autorun" 
      android:layout="@layout/preference" 
      android:summary="Autorun SMODE on boot" 
      android:title="Autorun SMODE" /> 
     <SwitchPreference 
      android:key="pref_wifi_control" 
      android:layout="@layout/preference" 
      android:selectable="false" 
      android:summary="Controls your Wi-Fi radio automatically based on hotspot availability" 
      android:title="Wi-Fi Radio Control" /> 
    </PreferenceCategory> 
</PreferenceScreen> 
+0

你的XML怎麼樣子? – Jokahero 2012-04-19 12:11:39

+0

我已更新我的問題。 – Zul 2012-04-19 12:26:23

+0

您是否找到了更快捷的替代方案?只是爲了確定用戶何時點擊複選框? – MatheusJardimB 2014-02-03 16:50:57

回答

5

通過在股票設置應用程序的源採取一看,就可以發現他們是如何做到的。

基本上,他們使用自定義的ArrayAdapter(很像你會用ListView做的)來顯示帶有Switch按鈕的行。而對於第二個屏幕,他們只需使用ActionBar中的CustomView。

我寫了an article with a sample code來展示你如何在你的項目中做到這一點。但要小心,這隻能在API Level 14或更高版本中引起注意,因此如果您定位舊設備,請保留舊樣式首選項屏幕。

+0

不錯的工作。這真的幫了我很多。謝謝澤維爾。 :) – Zul 2012-07-02 02:43:01

+0

不錯。說到這很荒謬,你必須編寫一個簡單的首選項屏幕,並使其適用於舊版,新版和平板電腦。一個人只需要在一個XML文件中聲明它,並且它應該在任何地方工作。期! – powder366 2013-02-23 15:06:48

+0

這個解決方案對於這樣一個小問題看起來太大了。是否有其他選擇來確定用戶何時點擊複選框或文本區域? – MatheusJardimB 2014-02-03 16:50:26

1

我在這裏看到2個問題:1.如何在開關區域外聽取偏好點擊? 2.如何在操作欄中放置一個開關?

我會回答問題1:

我創建了一個新的SwitchPreference類,並推翻了onClick方法什麼也不做。這可以防止在開關外部點擊時進行設置更改。

public class SwitchPreference extends android.preference.SwitchPreference { 
    @Override 
    protected void onClick() { 
    } 
} 

用法(XML):

<android.util.SwitchPreference 
    android:key="whatever" 
    android:title="Whatever" /> 

使用(JAVA):

SwitchPreference switchPreference = (SwitchPreference) findPreference("whatever"); 
switchPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { 
    @Override 
    public boolean onPreferenceClick(Preference preference) { 
     DialogUtils.showToast(Preferences.this, "Clicked outside switch"); 
     return true; 
    } 
}); 
switchPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 
    @Override 
    public boolean onPreferenceChange(Preference preference, Object newValue) { 
     DialogUtils.showToast(Preferences.this, "Clicked inside switch and setting changed"); 
     return true; 
    } 
}); 
+0

我喜歡它的一個很好的簡單的答案,但是當我嘗試這個代碼時,即使點擊了開關部分,也沒有采用「單擊內部開關和設置更改」分支。 – Marc 2015-01-11 16:40:13

+0

不適用於棒棒糖。 – 2015-01-11 18:55:50

1

我給這一個嘗試,有點掙扎。我想我會分享我的經驗。

起初我試了XGouchet的答案,因爲它的票數最多。該解決方案相當複雜,需要使用preference headers這是非常酷,但不適合我在做什麼。我決定最簡單的做法是將我的preferenceFragment包裝在一個普通的片段中,然後用常規的視圖僞裝switch preference。我挖了Android源的偏好以及與此

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" 
tools:context="com.lezyne.link.ui.homeScreen.settingsTab.SettingsFragment"> 

<FrameLayout 
    android:id="@+id/fragment_container" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center_horizontal"> 


</FrameLayout> 

<View 
    android:layout_width="fill_parent" 
    android:layout_height="1dp" 
    android:layout_marginLeft="15dp" 
    android:layout_marginRight="15dp" 
    android:background="#e1e1e1" /> 

<LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="?android:attr/selectableItemBackground" 
    android:gravity="center_vertical" 
    android:minHeight="?android:attr/listPreferredItemHeight" 
    android:orientation="horizontal" 
    android:paddingRight="?android:attr/scrollbarSize"> 

    <ImageView 
     android:id="@+id/icon" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" /> 

    <RelativeLayout 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="6dip" 
     android:layout_marginLeft="15dip" 
     android:layout_marginRight="6dip" 
     android:layout_marginTop="6dip" 
     android:layout_weight="1"> 

     <TextView 
      android:id="@+id/title" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:ellipsize="marquee" 
      android:fadingEdge="horizontal" 
      android:singleLine="true" 
      android:textAppearance="?android:attr/textAppearanceLarge" /> 

     <TextView 
      android:id="@+id/summary" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignLeft="@android:id/title" 
      android:layout_below="@android:id/title" 
      android:maxLines="4" 
      android:textAppearance="?android:attr/textAppearanceSmall" 
      android:textColor="?android:attr/textColorSecondary" /> 

    </RelativeLayout> 

    <!-- Preference should place its actual preference widget here. --> 
    <RelativeLayout 
     android:id="@+id/widget_frame" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:gravity="center_vertical" 
     android:orientation="vertical" 
     android:paddingEnd="36dp"> 


     <Switch 
      android:thumb="@drawable/switch_inner" 
      android:id="@+id/switch1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignParentEnd="true" /> 

     <TextView 
      android:id="@+id/textView6" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginLeft="2dp" 
      android:text="@string/Notifications" 
      android:textAppearance="?android:attr/textAppearanceMedium" /> 

    </RelativeLayout> 

</LinearLayout> 


<View 
    android:layout_width="fill_parent" 
    android:layout_height="1dp" 
    android:layout_marginLeft="15dp" 
    android:layout_marginRight="15dp" 
    android:background="#e1e1e1" /> 


</LinearLayout> 

頂部的FrameLayout裏上來得到像這樣

getChildFragmentManager() 
      .beginTransaction() 
      .replace(R.id.fragment_container, new SettingsPreferencesFragment(), "SettingsPreferencesFragment") 
      .commit(); 

偏好片段然後我可以得到分配我的點擊聽衆,我會在任何定期的看法。 SettingsPreferencesFragment只是完全標準的首選片段。

這個解決方案看起來不錯,但後來我發現了平板電腦上奇怪的佈局問題。我意識到如果讓這個解決方案在所有設備上看起來都很麻煩,我需要使用真正的switchPreference而不是假的。

==============解決方案2 ===============

AlikElzin-kilaka's solution是好的和簡單,但沒有奏效當我嘗試。我第二次嘗試確保我沒有犯錯。我一直玩耍,想出了一些似乎可行的東西。他有一個好點

2個問題在這裏:1.如何聽取偏好點擊 開關區域之外? 2.如何在操作欄中放置一個開關?

真的只是時間問題(1)是值得回答,因爲問題2已經回答了hereother places

我意識到以訪問的偏好的意見,唯一的辦法就是創建一個子類,並覆蓋onBind。所以我想出了這個SwitchPreference的子類,它爲交換機創建了單獨的點擊處理程序作爲整個視圖。它仍然是一個黑客。

public class MySwitchPreference extends SwitchPreference { 
public MySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
} 


public MySwitchPreference(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    getView(null,null); 

} 

public MySwitchPreference(Context context) { 
    super(context); 
} 

public interface SwitchClickListener{ 
    public void onSwitchClicked(boolean checked); 
    public void onPreferenceClicked(); 
} 
private SwitchClickListener listener = null; 
public void setSwitchClickListener(SwitchClickListener listener){ 
    this.listener = listener; 
} 

public Switch findSwitchWidget(View view){ 
    if (view instanceof Switch){ 
     return (Switch)view; 
    } 
    if (view instanceof ViewGroup){ 
     ViewGroup viewGroup = (ViewGroup)view; 
     for (int i = 0; i < viewGroup.getChildCount();i++){ 
      View child = viewGroup.getChildAt(i); 
      if (child instanceof ViewGroup){ 
       Switch result = findSwitchWidget(child); 
       if (result!=null) return result; 
      } 
      if (child instanceof Switch){ 
       return (Switch)child; 
      } 
     } 
    } 
    return null; 
} 

protected void onBindView (View view){ 
    super.onBindView(view); 

    final Switch switchView = findSwitchWidget(view); 
    if (switchView!=null){ 
     switchView.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       if (listener!=null) listener.onSwitchClicked(switchView.isChecked()); 
      } 
     }); 
     switchView.setFocusable(true); 
     switchView.setEnabled(true); 
    } 

    view.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      if (listener!=null) listener.onPreferenceClicked(); 
     } 
    }); 

} 
} 

它使用遞歸函數findSwitchWidget遍歷樹直到找到一個Switch。我寧願寫這樣的代碼:

Switch switchView = view.findViewById(android.R.id.switchView); 

但似乎沒有一種方法來獲得我知道的內部id值。無論如何,一旦我們有實際的開關,我們可以分配監聽器和容器視圖。切換首選項不會自動更新,因此必須自行保存該首選項。

MySwitchPreference switchPreference = (MySwitchPreference) findPreference("whatever"); 
    switchPreference.setSwitchClickListener(new MySwitchPreference.SwitchClickListener() { 
     @Override 
     public void onSwitchClicked(boolean checked) { 
      //Save the preference value here 
     } 

     @Override 
     public void onPreferenceClicked() { 
      //Launch the new preference screen or activity here 
     } 
    }); 

希望這第二黑客不會回來咬我。

任何人都可以看到這種方法的任何潛在缺陷?

我也把代碼輕微改進版在github https://gist.github.com/marchold/45e22839eb94aa14dfb5

相關問題