SwitchPreference是android4.0新加的一个控件,类似于CheckBoxPreference,继承自TwoStatePreference类,顾名思义,有两种状态,并含有一个Switch控件。
当我们直接调用SwitchPreference控件时,会发现无论我们点击SwitchPreference控件的任何区域,Switch状态都会改变。所以,当我们想要一种效果:只是点击SwitchPreference中的Switch控件才能改变其状态时,直接调用SwitchPreference显然行不通。这里有两种方法。
方法一:继承并改写SwitchPreference类。
查看SwitchPreference.java源码,发现其中并没有多少内容,其中值得关注的也就是布局时会自动调用的onBindView()方法:
@Override
protected void onBindView(View view) {
super.onBindView(view);
View checkableView = view.findViewById(com.android.internal.R.id.switchWidget);
if (checkableView != null && checkableView instanceof Checkable) {
((Checkable) checkableView).setChecked(mChecked);
sendAccessibilityEvent(checkableView);
if (checkableView instanceof Switch) {
final Switch switchView = (Switch) checkableView;
switchView.setTextOn(mSwitchOn);
switchView.setTextOff(mSwitchOff);
switchView.setOnCheckedChangeListener(mListener);
}
}
syncSummaryView(view);
}
可以发现其中就是对Switch控件的布局和监听。想要找到整个SwitchPreference的点击事件,还要追溯到其父类TwoStatePreference中,对应方法如下:
@Override
protected void onClick() {
super.onClick();
boolean newValue = !isChecked();
mSendClickAccessibilityEvent = true;
if (!callChangeListener(newValue)) {
return;
}
setChecked(newValue);
}
可以看出只要点击SwitchPreference就会导致isCheck()改变从而改变Switch状态。
既然知道原因,我们写一个类继承自SwitchPreference,然后重写其onClick()方法,即可。如下:
public class HftSwitchPreference extends SwitchPreference {
... ...
@Override
protected void onClick() {
}
}
如果没有其他需要,其他方法直接调用super即可。这样,当我们再次点击SwitchPreference中除Switch意外的区域时,Switch状态就不会随之变更。至于点击这些区域想要做什么处理(如跳转等),自己在onClick()中添加相应代码即可。
方法二:重写Preference类。
SwitchPreference、CheckBoxPreference等类似的空间,都是Preference类的延伸。查看Preference类对于的布局文件preference.xml,可以发现最后有这么一段:
<LinearLayout android:id="@+android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical" />
也就是Preference视图最右边的部分。这部分的布局对应Preference的android:widgetLayout属性。如下,我自写一个HftPreference类继承自Preference:
public class HftPreference extends Preference {
... ...
}
假设该类包名为com.hft.preference,那么在相应的xml布局文件中可这样定义该控件:
<com.hft.preference.HftPreference
android:key="wifi_settings"
android:fragment="com.android.settings.wifi.WifiSettings"
android:title="@string/wifi_settings_title"
android:icon="@drawable/ic_settings_wireless"
android:widgetLayout="@layout/hft_switch"/>
这里主要看android:widgetLayout属性,其对应的hft_switch.xml仅定义了一个Switch控件,当然这里是讲关于SwitchPreference的,如果想定义成其他布局文件同样完全可以。hft_switch.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/hft_switch"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:focusable="false">
</Switch>
如果其他什么都不做修改,现在这个HftPreference控件外表已经和SwitchPreference控件一样。特别注意,这里一定要添加android:focusable="false"属性,否则Switch控件一直处于聚焦状态,将屏蔽Preference的点击事件。
至于Switch控件的点击事件,应在HftPreference的onBindView()中处理,而Preference点击事件则在onClick()中处理。如下:
@Override
protected void onBindView(View view) {
super.onBindView(view);
Switch hftSwitch = (Switch) view.findViewById(R.id.hft_switch);
hftSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
.. ...
}
});
}
@Override
protected void onClick() {
super.onClick();
//Preference的点击事件
}