2012-04-19 41 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

相关问题