作为Android的初学者,很多地方理解不深刻,这是自己的第一篇博客,当作是纪念了。
现在的需求是,将CheckBoxPreference中的CheckBox换成一个已经写好的,有动效Switch控件,增加切换时的动效。
虽然在preference.xml中可以指定widgetLayout的样式,也就是CheckBox可换成其他的控件
<pre name="code" class="html"><CheckBoxPreference
android:defaultValue="true"
android:key="pref_key_show_recent_recipents"
android:layout="@layout/cp_layout_preference"
android:summary="@string/smsmms_recent_recipents_summary"
android:title="@string/smsmms_recent_recipents"
android:widgetLayout="@layout/cp_layout_checkbox_switchbtn" />
<pre name="code" class="html">cp_layout_checkbox_switchbtn.xml是Switch的样式,但是这样的修改会出现一个问题,当点击CheckBoxPreference时,可以达到设置的效果,但是当点击Switch这个控件时,不能达到设置的效果。也就是说Switch的点击事件没有与Preference的点击事件关联起来。后来在网上发现Android4.0之后的版本新增了SwitchPreference控件,正好与我的需求相吻合,于是便将布局改成了如下
</pre><pre>
<SwitchPreference
android:defaultValue="true"
android:key="pref_key_show_recent_recipents"
android:layout="@layout/cp_layout_preference"
android:summary="@string/smsmms_recent_recipents_summary"
android:title="@string/smsmms_recent_recipents"
android:widgetLayout="@layout/cp_layout_checkbox_switchbtn" />
这时候点击Switch控件,是能够起到设置效果的,但是新的问题来了,在整个设置页面中,有多个这样的SwitchPreference控件,当点击其中一个Switch时,其他SwitchPreference中的Switch控件的状态会同步的更新一次。
由于切换是有动效的,点击其中一个Switch,会清楚的看到其他的Switch也会有一次动态的切换,虽然其他的Switch最终的开关状态,但是切换的过程还是有了,通过查看SwitchPreference源码,发现在onBingView函数中,每次都会更新按钮的状态。
protected void onBindView(View view) {
super.onBindView(view);
View checkableView = view.findViewById(com.android.internal.R.id.switchWidget);
if (checkableView != null && checkableView instanceof Checkable) {
if (checkableView instanceof Switch) {
final Switch switchView = (Switch) checkableView;
switchView.setOnCheckedChangeListener(null);
}
<span style="color:#ff0000;">((Checkable) checkableView).setChecked(mChecked);</span>
if (checkableView instanceof Switch) {
final Switch switchView = (Switch) checkableView;
switchView.setTextOn(mSwitchOn);
switchView.setTextOff(mSwitchOff);
switchView.setOnCheckedChangeListener(mListener);
}
}
syncSummaryView(view);
}
从中发现每次更新状态时,都会重新设置一次mChecked的值,而正好我的动效能够清晰的看到这一次切换的过程。
分析原因,应该是每次更新时,不管Switch的check值与Preference的check值是否一次,都会切换一次Switch状态。后来发现如果切换的过程不采用动效,就看不出来这一过程了,所以我仿照SwitchPreference的实现方式,新建了MySwitchPreference类,同样继承了TwoStatePreference,不同的是在更新时加入一个判断
protected void onBindView(View view) {
super.onBindView(view);
View checkableView = view.findViewById(android.R.id.checkbox);
if (checkableView != null && checkableView instanceof Checkable) {
if (checkableView instanceof Switch) {
<span style="color:#ff0000;">Switch mSwitchView = (Switch) checkableView;
mSwitchView.setOnCheckedChangeListener(null);
if (isChecked() != mSwitchView.isChecked()) {
mSwitchView.setChecked(isChecked());
} else {
mSwitchView.setCheckedImmediately(isChecked());//没有动画的切换状态
}</span>
mSwitchView.setOnCheckedChangeListener(mCheckedChangeListener);
}
}
}
只有当状态不一样时,需要动效的切换,状态一样时,直接切换,没有动效。这样在视觉上便觉得只有那一个点击的Switch的状态切换了。
虽然问题解决了,但是仍然有一些疑问:
<span style="color:#ff0000;">mSwitchView.setChecked(boolean b)</span>
这个函数实现时是有判断的,如果新设置的值与原先的值相同,就直接return了,也就是说只有设置不同的值时才会有动态切换的效果。既然我这里的Switch每次都会重新设置值,那么说明每次更新时的值都与原先的值不同,但是为什么不同呢?
经过分析,原因应该是在初始化MySwitchPreference时,没有将Switch与Preference的checked状态进行同步,而Switch的默认状态是false,导致有些Preference的状态被初始化成true,导致每次调用onBindView刷新界面时,会出现Preference为true的控件中的Switch被重新设置了状态true,也就是重新更新了一次。
到底应该如何解决这个问题呢?如何将Preference的初始化状态同时传递给Switch呢,不知道各位看官有没有明白我说的,有没有什么好的建议?